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