* Copyright 2001-2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "JobListView.h"
#include <stdio.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Locale.h>
#include <MimeType.h>
#include <Roster.h>
#include <StringFormat.h>
#include <Window.h>
#include "pr_server.h"
#include "Globals.h"
#include "Jobs.h"
#include "Messages.h"
#include "SpoolFolder.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "JobListView"
JobListView::JobListView(BRect frame)
:
Inherited(frame, "jobs_list", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL,
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE)
{
}
JobListView::~JobListView()
{
while (!IsEmpty())
delete RemoveItem((int32)0);
}
void
JobListView::AttachedToWindow()
{
Inherited::AttachedToWindow();
SetSelectionMessage(new BMessage(kMsgJobSelected));
SetTarget(Window());
}
void
JobListView::SetSpoolFolder(SpoolFolder* folder)
{
while (!IsEmpty())
delete RemoveItem((int32)0);
if (folder == NULL)
return;
for (int32 i = 0; i < folder->CountJobs(); i++)
AddJob(folder->JobAt(i));
}
JobItem*
JobListView::FindJob(Job* job) const
{
const int32 n = CountItems();
for (int32 i = 0; i < n; i++) {
JobItem* item = dynamic_cast<JobItem*>(ItemAt(i));
if (item && item->GetJob() == job)
return item;
}
return NULL;
}
JobItem*
JobListView::SelectedItem() const
{
return dynamic_cast<JobItem*>(ItemAt(CurrentSelection()));
}
void
JobListView::AddJob(Job* job)
{
AddItem(new JobItem(job));
Invalidate();
}
void
JobListView::RemoveJob(Job* job)
{
JobItem* item = FindJob(job);
if (item) {
RemoveItem(item);
delete item;
Invalidate();
}
}
void
JobListView::UpdateJob(Job* job)
{
JobItem* item = FindJob(job);
if (item) {
item->Update();
InvalidateItem(IndexOf(item));
}
}
void
JobListView::RestartJob()
{
JobItem* item = SelectedItem();
if (item && item->GetJob()->Status() == kFailed) {
item->GetJob()->SetStatus(kWaiting);
}
}
void
JobListView::CancelJob()
{
JobItem* item = SelectedItem();
if (item && item->GetJob()->Status() != kProcessing) {
item->GetJob()->SetStatus(kFailed);
item->GetJob()->Remove();
}
}
JobItem::JobItem(Job* job)
:
BListItem(0, false),
fJob(job),
fIcon(NULL)
{
fJob->Acquire();
Update();
}
JobItem::~JobItem()
{
fJob->Release();
delete fIcon;
}
void
JobItem::Update()
{
BNode node(&fJob->EntryRef());
if (node.InitCheck() != B_OK)
return;
node.ReadAttrString(PSRV_SPOOL_ATTR_DESCRIPTION, &fName);
BString mimeType;
node.ReadAttrString(PSRV_SPOOL_ATTR_MIMETYPE, &mimeType);
entry_ref ref;
if (fIcon == NULL && be_roster->FindApp(mimeType.String(), &ref) == B_OK) {
BRect rect(BPoint(0, 0), be_control_look->ComposeIconSize(B_LARGE_ICON));
fIcon = new BBitmap(rect, B_RGBA32);
BMimeType type(mimeType.String());
if (type.GetIcon(fIcon, (icon_size)(rect.IntegerHeight() + 1)) != B_OK) {
delete fIcon;
fIcon = NULL;
}
}
fPages = "";
int32 pages;
static BStringFormat format(B_TRANSLATE("{0, plural, "
"=-1{??? pages}"
"=1{# page}"
"other{# pages}}"));
if (node.ReadAttr(PSRV_SPOOL_ATTR_PAGECOUNT,
B_INT32_TYPE, 0, &pages, sizeof(pages)) == sizeof(pages)) {
format.Format(fPages, pages);
} else {
format.Format(fPages, -1);
}
fSize = "";
off_t size;
if (node.GetSize(&size) == B_OK) {
char buffer[80];
snprintf(buffer, sizeof(buffer), B_TRANSLATE("%.2f KB"),
size / 1024.0);
fSize = buffer;
}
fStatus = "";
switch (fJob->Status()) {
case kWaiting:
fStatus = B_TRANSLATE("Waiting");
break;
case kProcessing:
fStatus = B_TRANSLATE("Processing");
break;
case kFailed:
fStatus = B_TRANSLATE("Failed");
break;
case kCompleted:
fStatus = B_TRANSLATE("Completed");
break;
default:
fStatus = B_TRANSLATE("Unknown status");
}
}
void
JobItem::Update(BView *owner, const BFont *font)
{
BListItem::Update(owner, font);
font_height height;
font->GetHeight(&height);
SetHeight((height.ascent + height.descent + height.leading) * 2.0 + 8.0);
}
void
JobItem::DrawItem(BView *owner, BRect, bool complete)
{
BListView* list = dynamic_cast<BListView*>(owner);
if (list) {
BFont font;
owner->GetFont(&font);
font_height height;
font.GetHeight(&height);
float fntheight = height.ascent + height.descent + height.leading;
BRect bounds = list->ItemFrame(list->IndexOf(this));
rgb_color color = owner->ViewColor();
rgb_color oldLowColor = owner->LowColor();
rgb_color oldHighColor = owner->HighColor();
if (IsSelected())
color = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
owner->SetHighColor(color);
owner->SetLowColor(color);
owner->FillRect(bounds);
owner->SetLowColor(oldLowColor);
owner->SetHighColor(oldHighColor);
BPoint iconPt(bounds.LeftTop() + BPoint(2.0, 2.0));
float iconHeight = B_MINI_ICON;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (fIcon)
iconHeight = fIcon->Bounds().Height();
#endif
BPoint leftTop(bounds.LeftTop() + BPoint(12.0 + iconHeight, 2.0));
BPoint namePt(leftTop + BPoint(0.0, fntheight));
BPoint statusPt(leftTop + BPoint(0.0, fntheight * 2.0));
float x = owner->StringWidth(fPages.String()) + 32.0;
BPoint pagePt(bounds.RightTop() + BPoint(-x, fntheight));
BPoint sizePt(bounds.RightTop() + BPoint(-x, fntheight * 2.0));
drawing_mode mode = owner->DrawingMode();
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
owner->SetDrawingMode(B_OP_ALPHA);
#else
owner->SetDrawingMode(B_OP_OVER);
#endif
if (fIcon)
owner->DrawBitmap(fIcon, iconPt);
BString name = fName;
owner->TruncateString(&name, B_TRUNCATE_MIDDLE, pagePt.x - namePt.x);
owner->DrawString(name.String(), name.Length(), namePt);
BString status = fStatus;
owner->TruncateString(&status, B_TRUNCATE_MIDDLE, sizePt.x - statusPt.x);
owner->DrawString(status.String(), status.Length(), statusPt);
owner->DrawString(fPages.String(), fPages.Length(), pagePt);
owner->DrawString(fSize.String(), fSize.Length(), sizePt);
owner->SetDrawingMode(mode);
}
}