1/*
2 * Copyright 2001-2010, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Pfeiffer
7 */
8
9
10#include "JobListView.h"
11
12#include <stdio.h>
13
14#include <Catalog.h>
15#include <Locale.h>
16#include <MimeType.h>
17#include <Roster.h>
18#include <Window.h>
19
20#include "pr_server.h"
21#include "Globals.h"
22#include "Jobs.h"
23#include "Messages.h"
24#include "SpoolFolder.h"
25
26
27#undef B_TRANSLATION_CONTEXT
28#define B_TRANSLATION_CONTEXT "JobListView"
29
30
31// #pragma mark -- JobListView
32
33
34JobListView::JobListView(BRect frame)
35	:
36	Inherited(frame, "jobs_list", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL,
37		B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE)
38{
39}
40
41
42JobListView::~JobListView()
43{
44	while (!IsEmpty())
45		delete RemoveItem((int32)0);
46}
47
48
49void
50JobListView::AttachedToWindow()
51{
52	Inherited::AttachedToWindow();
53
54	SetSelectionMessage(new BMessage(kMsgJobSelected));
55	SetTarget(Window());
56}
57
58
59void
60JobListView::SetSpoolFolder(SpoolFolder* folder)
61{
62	// clear list
63	while (!IsEmpty())
64		delete RemoveItem((int32)0);
65
66	if (folder == NULL)
67		return;
68
69	// Find directory containing printer definition nodes
70	for (int32 i = 0; i < folder->CountJobs(); i++)
71		AddJob(folder->JobAt(i));
72}
73
74
75JobItem*
76JobListView::FindJob(Job* job) const
77{
78	const int32 n = CountItems();
79	for (int32 i = 0; i < n; i++) {
80		JobItem* item = dynamic_cast<JobItem*>(ItemAt(i));
81		if (item && item->GetJob() == job)
82			return item;
83	}
84	return NULL;
85}
86
87
88JobItem*
89JobListView::SelectedItem() const
90{
91	return dynamic_cast<JobItem*>(ItemAt(CurrentSelection()));
92}
93
94
95void
96JobListView::AddJob(Job* job)
97{
98	AddItem(new JobItem(job));
99	Invalidate();
100}
101
102
103void
104JobListView::RemoveJob(Job* job)
105{
106	JobItem* item = FindJob(job);
107	if (item) {
108		RemoveItem(item);
109		delete item;
110		Invalidate();
111	}
112}
113
114
115void
116JobListView::UpdateJob(Job* job)
117{
118	JobItem* item = FindJob(job);
119	if (item) {
120		item->Update();
121		InvalidateItem(IndexOf(item));
122	}
123}
124
125
126void
127JobListView::RestartJob()
128{
129	JobItem* item = SelectedItem();
130	if (item && item->GetJob()->Status() == kFailed) {
131		// setting the state changes the file attribute and
132		// we will receive a notification from SpoolFolder
133		item->GetJob()->SetStatus(kWaiting);
134	}
135}
136
137
138void
139JobListView::CancelJob()
140{
141	JobItem* item = SelectedItem();
142	if (item && item->GetJob()->Status() != kProcessing) {
143		item->GetJob()->SetStatus(kFailed);
144		item->GetJob()->Remove();
145	}
146}
147
148
149// #pragma mark -- JobItem
150
151
152JobItem::JobItem(Job* job)
153	:
154	BListItem(0, false),
155	fJob(job),
156	fIcon(NULL)
157{
158	fJob->Acquire();
159	Update();
160}
161
162
163JobItem::~JobItem()
164{
165	fJob->Release();
166	delete fIcon;
167}
168
169
170void
171JobItem::Update()
172{
173	BNode node(&fJob->EntryRef());
174	if (node.InitCheck() != B_OK)
175		return;
176
177	node.ReadAttrString(PSRV_SPOOL_ATTR_DESCRIPTION, &fName);
178
179	BString mimeType;
180	node.ReadAttrString(PSRV_SPOOL_ATTR_MIMETYPE, &mimeType);
181
182	entry_ref ref;
183	if (fIcon == NULL && be_roster->FindApp(mimeType.String(), &ref) == B_OK) {
184#ifdef HAIKU_TARGET_PLATFORM_HAIKU
185		font_height fontHeight;
186		be_plain_font->GetHeight(&fontHeight);
187		float height = (fontHeight.ascent + fontHeight.descent
188			+ fontHeight.leading) * 2.0;
189		BRect rect(0, 0, height, height);
190		fIcon = new BBitmap(rect, B_RGBA32);
191#else
192		BRect rect(0, 0, B_MINI_ICON - 1, B_MINI_ICON - 1);
193		fIcon = new BBitmap(rect, B_CMAP8);
194#endif
195		BMimeType type(mimeType.String());
196		if (type.GetIcon(fIcon, B_MINI_ICON) != B_OK) {
197			delete fIcon;
198			fIcon = NULL;
199		}
200	}
201
202	fPages = "";
203	int32 pages;
204	if (node.ReadAttr(PSRV_SPOOL_ATTR_PAGECOUNT,
205		B_INT32_TYPE, 0, &pages, sizeof(pages)) == sizeof(pages)) {
206		fPages << pages;
207		if (pages > 1)
208			fPages << " " << B_TRANSLATE("pages") << ".";
209		else
210			fPages << " " << B_TRANSLATE("page") << ".";
211	} else {
212		fPages << "??? " << B_TRANSLATE("pages") << ".";
213	}
214
215	fSize = "";
216	off_t size;
217	if (node.GetSize(&size) == B_OK) {
218		char buffer[80];
219		snprintf(buffer, sizeof(buffer), B_TRANSLATE("%.2f KB"),
220			size / 1024.0);
221		fSize = buffer;
222	}
223
224	fStatus = "";
225	switch (fJob->Status()) {
226		case kWaiting:
227			fStatus = B_TRANSLATE("Waiting");
228			break;
229
230		case kProcessing:
231			fStatus = B_TRANSLATE("Processing");
232			break;
233
234		case kFailed:
235			fStatus = B_TRANSLATE("Failed");
236			break;
237
238		case kCompleted:
239			fStatus = B_TRANSLATE("Completed");
240			break;
241
242		default:
243			fStatus = B_TRANSLATE("Unknown status");
244	}
245}
246
247
248void
249JobItem::Update(BView *owner, const BFont *font)
250{
251	BListItem::Update(owner, font);
252
253	font_height height;
254	font->GetHeight(&height);
255
256	SetHeight((height.ascent + height.descent + height.leading) * 2.0 + 8.0);
257}
258
259
260void
261JobItem::DrawItem(BView *owner, BRect, bool complete)
262{
263	BListView* list = dynamic_cast<BListView*>(owner);
264	if (list) {
265		BFont font;
266		owner->GetFont(&font);
267
268		font_height height;
269		font.GetHeight(&height);
270		float fntheight = height.ascent + height.descent + height.leading;
271
272		BRect bounds = list->ItemFrame(list->IndexOf(this));
273
274		rgb_color color = owner->ViewColor();
275		rgb_color oldViewColor = color;
276		rgb_color oldLowColor = owner->LowColor();
277		rgb_color oldHighColor = owner->HighColor();
278
279		if (IsSelected())
280			color = tint_color(color, B_HIGHLIGHT_BACKGROUND_TINT);
281
282		owner->SetViewColor(color);
283		owner->SetHighColor(color);
284		owner->SetLowColor(color);
285
286		owner->FillRect(bounds);
287
288		owner->SetLowColor(oldLowColor);
289		owner->SetHighColor(oldHighColor);
290
291		BPoint iconPt(bounds.LeftTop() + BPoint(2.0, 2.0));
292		float iconHeight = B_MINI_ICON;
293#ifdef HAIKU_TARGET_PLATFORM_HAIKU
294		if (fIcon)
295			iconHeight = fIcon->Bounds().Height();
296#endif
297		BPoint leftTop(bounds.LeftTop() + BPoint(12.0 + iconHeight, 2.0));
298		BPoint namePt(leftTop + BPoint(0.0, fntheight));
299		BPoint statusPt(leftTop + BPoint(0.0, fntheight * 2.0));
300
301		float x = owner->StringWidth(fPages.String()) + 32.0;
302		BPoint pagePt(bounds.RightTop() + BPoint(-x, fntheight));
303		BPoint sizePt(bounds.RightTop() + BPoint(-x, fntheight * 2.0));
304
305		drawing_mode mode = owner->DrawingMode();
306#ifdef HAIKU_TARGET_PLATFORM_HAIKU
307	owner->SetDrawingMode(B_OP_ALPHA);
308#else
309	owner->SetDrawingMode(B_OP_OVER);
310#endif
311
312		if (fIcon)
313			owner->DrawBitmap(fIcon, iconPt);
314
315		// left of item
316		owner->DrawString(fName.String(), fName.Length(), namePt);
317		owner->DrawString(fStatus.String(), fStatus.Length(), statusPt);
318
319		// right of item
320		owner->DrawString(fPages.String(), fPages.Length(), pagePt);
321		owner->DrawString(fSize.String(), fSize.Length(), sizePt);
322
323		owner->SetDrawingMode(mode);
324		owner->SetViewColor(oldViewColor);
325	}
326}
327