2 * Copyright 2001-2010, Haiku.
3 * Distributed under the terms of the MIT License.
10 #include "PrinterListView.h"
12 #include <Application.h>
15 #include <Directory.h>
16 #include <IconUtils.h>
20 #include <Resources.h>
23 #include "pr_server.h"
26 #include "PrintersWindow.h"
27 #include "SpoolFolder.h"
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "PrinterListView"
34 // #pragma mark -- PrinterListView
37 PrinterListView::PrinterListView(BRect frame
)
38 : Inherited(frame
, "printers_list", B_SINGLE_SELECTION_LIST
, B_FOLLOW_ALL
,
39 B_WILL_DRAW
| B_FRAME_EVENTS
| B_NAVIGABLE
| B_FULL_UPDATE_ON_RESIZE
),
43 fLayoutData
.fLeftColumnMaximumWidth
= 100;
44 fLayoutData
.fRightColumnMaximumWidth
= 100;
48 PrinterListView::~PrinterListView()
51 delete RemoveItem((int32
)0);
56 PrinterListView::BuildPrinterList()
60 delete RemoveItem((int32
)0);
62 // Find directory containing printer definition nodes
64 if (find_directory(B_USER_PRINTERS_DIRECTORY
, &path
) != B_OK
)
67 BDirectory
dir(path
.Path());
68 if (dir
.InitCheck() != B_OK
)
72 while(dir
.GetNextEntry(&entry
) == B_OK
) {
73 BDirectory
printer(&entry
);
74 _AddPrinter(printer
, false);
77 _LayoutPrinterItems();
82 PrinterListView::AttachedToWindow()
84 Inherited::AttachedToWindow();
86 SetSelectionMessage(new BMessage(kMsgPrinterSelected
));
87 SetInvocationMessage(new BMessage(kMsgMakeDefaultPrinter
));
91 if (find_directory(B_USER_PRINTERS_DIRECTORY
, &path
) != B_OK
)
94 BDirectory
dir(path
.Path());
95 if (dir
.InitCheck() != B_OK
) {
96 // directory has to exist in order to start watching it
97 if (create_directory(path
.Path(), 0777) != B_OK
)
99 dir
.SetTo(path
.Path());
102 fFolder
= new FolderWatcher(Window(), dir
, true);
103 fFolder
->SetListener(this);
107 // Select active printer
108 BString
activePrinterName(ActivePrinterName());
109 for (int32 i
= 0; i
< CountItems(); i
++) {
110 PrinterItem
* item
= dynamic_cast<PrinterItem
*>(ItemAt(i
));
111 if (item
!= NULL
&& item
->Name() == activePrinterName
) {
113 fActivePrinter
= item
;
121 PrinterListView::QuitRequested()
129 PrinterListView::UpdateItem(PrinterItem
* item
)
131 item
->UpdatePendingJobs();
132 InvalidateItem(IndexOf(item
));
137 PrinterListView::ActivePrinter() const
139 return fActivePrinter
;
144 PrinterListView::SetActivePrinter(PrinterItem
* item
)
146 fActivePrinter
= item
;
151 PrinterListView::SelectedItem() const
153 return dynamic_cast<PrinterItem
*>(ItemAt(CurrentSelection()));
157 // FolderListener interface
160 PrinterListView::EntryCreated(node_ref
* node
, entry_ref
* entry
)
162 BDirectory
printer(node
);
163 _AddPrinter(printer
, true);
168 PrinterListView::EntryRemoved(node_ref
* node
)
170 PrinterItem
* item
= _FindItem(node
);
172 if (item
== fActivePrinter
)
173 fActivePrinter
= NULL
;
182 PrinterListView::AttributeChanged(node_ref
* node
)
184 BDirectory
printer(node
);
185 _AddPrinter(printer
, true);
192 PrinterListView::_AddPrinter(BDirectory
& printer
, bool calculateLayout
)
196 // If the entry is a directory
197 if (printer
.InitCheck() == B_OK
198 && printer
.GetNodeRef(&node
) == B_OK
199 && _FindItem(&node
) == NULL
200 && printer
.ReadAttrString(PSRV_PRINTER_ATTR_STATE
, &state
) == B_OK
201 && state
== "free") {
202 // Check it's Mime type for a spool director
203 BNodeInfo
info(&printer
);
206 if (info
.GetType(buffer
) == B_OK
207 && strcmp(buffer
, PSRV_PRINTER_FILETYPE
) == 0) {
208 // Yes, it is a printer definition node
209 AddItem(new PrinterItem(static_cast<PrintersWindow
*>(Window()),
210 printer
, fLayoutData
));
212 _LayoutPrinterItems();
219 PrinterListView::_LayoutPrinterItems()
221 float& leftColumnMaximumWidth
= fLayoutData
.fLeftColumnMaximumWidth
;
222 float& rightColumnMaximumWidth
= fLayoutData
.fRightColumnMaximumWidth
;
224 for (int32 i
= 0; i
< CountItems(); i
++) {
225 PrinterItem
* item
= static_cast<PrinterItem
*>(ItemAt(i
));
227 float leftColumnWidth
= 0;
228 float rightColumnWidth
= 0;
229 item
->GetColumnWidth(this, leftColumnWidth
, rightColumnWidth
);
231 leftColumnMaximumWidth
= MAX(leftColumnMaximumWidth
,
233 rightColumnMaximumWidth
= MAX(rightColumnMaximumWidth
,
242 PrinterListView::_FindItem(node_ref
* node
) const
244 for (int32 i
= CountItems() - 1; i
>= 0; i
--) {
245 PrinterItem
* item
= dynamic_cast<PrinterItem
*>(ItemAt(i
));
247 if (item
&& item
->Node()->GetNodeRef(&ref
) == B_OK
&& ref
== *node
)
255 // #pragma mark -- PrinterItem
258 BBitmap
* PrinterItem::sIcon
= NULL
;
259 BBitmap
* PrinterItem::sSelectedIcon
= NULL
;
262 PrinterItem::PrinterItem(PrintersWindow
* window
, const BDirectory
& node
,
263 PrinterListLayoutData
& layoutData
)
264 : BListItem(0, false),
267 fLayoutData(layoutData
)
269 BRect
rect(0, 0, B_LARGE_ICON
- 1, B_LARGE_ICON
- 1);
271 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
272 sIcon
= new BBitmap(rect
, B_RGBA32
);
274 sIcon
= new BBitmap(rect
, B_CMAP8
);
276 BMimeType
type(PSRV_PRINTER_FILETYPE
);
277 type
.GetIcon(sIcon
, B_LARGE_ICON
);
280 if (sIcon
&& sIcon
->IsValid() && sSelectedIcon
== NULL
) {
281 const float checkMarkIconSize
= 20.0;
282 BBitmap
*checkMark
= _LoadVectorIcon("check_mark_icon",
284 if (checkMark
&& checkMark
->IsValid()) {
285 sSelectedIcon
= new BBitmap(rect
, B_RGBA32
, true);
286 if (sSelectedIcon
&& sSelectedIcon
->IsValid()) {
287 // draw check mark at bottom left over printer icon
288 BView
*view
= new BView(rect
, "offscreen", B_FOLLOW_ALL
,
290 float y
= rect
.Height() - checkMark
->Bounds().Height();
291 sSelectedIcon
->Lock();
292 sSelectedIcon
->AddChild(view
);
293 view
->DrawBitmap(sIcon
);
294 view
->SetDrawingMode(B_OP_ALPHA
);
295 view
->DrawBitmap(checkMark
, BPoint(0, y
));
298 sSelectedIcon
->Unlock();
305 // Get Name of printer
306 _GetStringProperty(PSRV_PRINTER_ATTR_PRT_NAME
, fName
);
307 _GetStringProperty(PSRV_PRINTER_ATTR_COMMENTS
, fComments
);
308 _GetStringProperty(PSRV_PRINTER_ATTR_TRANSPORT
, fTransport
);
309 _GetStringProperty(PSRV_PRINTER_ATTR_TRANSPORT_ADDR
, fTransportAddress
);
310 _GetStringProperty(PSRV_PRINTER_ATTR_DRV_NAME
, fDriverName
);
313 if (find_directory(B_USER_PRINTERS_DIRECTORY
, &path
) != B_OK
)
316 // Setup spool folder
317 path
.Append(fName
.String());
318 BDirectory
dir(path
.Path());
319 if (dir
.InitCheck() == B_OK
) {
320 fFolder
= new SpoolFolder(window
, this, dir
);
326 PrinterItem::~PrinterItem()
333 PrinterItem::GetColumnWidth(BView
* view
, float& leftColumn
, float& rightColumn
)
336 view
->GetFont(&font
);
338 leftColumn
= font
.StringWidth(fName
.String());
339 leftColumn
= MAX(leftColumn
, font
.StringWidth(fDriverName
.String()));
341 rightColumn
= font
.StringWidth(fPendingJobs
.String());
342 rightColumn
= MAX(rightColumn
, font
.StringWidth(fTransport
.String()));
343 rightColumn
= MAX(rightColumn
, font
.StringWidth(fComments
.String()));
348 PrinterItem::Update(BView
*owner
, const BFont
*font
)
350 BListItem::Update(owner
,font
);
353 font
->GetHeight(&height
);
355 SetHeight((height
.ascent
+ height
.descent
+ height
.leading
) * 3.0 + 8.0);
359 bool PrinterItem::Remove(BListView
* view
)
362 if (GetPrinterServerMessenger(msgr
) == B_OK
) {
363 BMessage
script(B_DELETE_PROPERTY
);
364 script
.AddSpecifier("Printer", view
->IndexOf(this));
367 if (msgr
.SendMessage(&script
,&reply
) == B_OK
)
375 PrinterItem::DrawItem(BView
*owner
, BRect
/*bounds*/, bool complete
)
377 BListView
* list
= dynamic_cast<BListView
*>(owner
);
382 owner
->GetFont(&font
);
385 font
.GetHeight(&height
);
387 float fntheight
= height
.ascent
+ height
.descent
+ height
.leading
;
389 BRect bounds
= list
->ItemFrame(list
->IndexOf(this));
391 rgb_color color
= owner
->ViewColor();
392 rgb_color oldLowColor
= owner
->LowColor();
393 rgb_color oldHighColor
= owner
->HighColor();
396 color
= ui_color(B_LIST_SELECTED_BACKGROUND_COLOR
);
398 owner
->SetLowColor(color
);
399 owner
->SetHighColor(color
);
401 owner
->FillRect(bounds
);
403 owner
->SetLowColor(oldLowColor
);
404 owner
->SetHighColor(oldHighColor
);
406 float iconColumnWidth
= B_LARGE_ICON
+ 8.0;
407 float x
= iconColumnWidth
;
408 BPoint
iconPt(bounds
.LeftTop() + BPoint(2.0, 2.0));
409 BPoint
namePt(iconPt
+ BPoint(x
, fntheight
));
410 BPoint
driverPt(iconPt
+ BPoint(x
, fntheight
* 2.0));
411 BPoint
defaultPt(iconPt
+ BPoint(x
, fntheight
* 3.0));
412 BPoint
transportPt(iconPt
+ BPoint(x
, fntheight
* 3.0));
414 float totalWidth
= bounds
.Width() - iconColumnWidth
;
415 float maximumWidth
= fLayoutData
.fLeftColumnMaximumWidth
+
416 fLayoutData
.fRightColumnMaximumWidth
;
418 if (totalWidth
< maximumWidth
) {
419 width
= fLayoutData
.fRightColumnMaximumWidth
* totalWidth
/
422 width
= fLayoutData
.fRightColumnMaximumWidth
;
425 BPoint
pendingPt(bounds
.right
- width
- 8.0, namePt
.y
);
426 BPoint
commentPt(bounds
.right
- width
- 8.0, driverPt
.y
);
429 drawing_mode mode
= owner
->DrawingMode();
430 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
431 owner
->SetDrawingMode(B_OP_ALPHA
);
433 owner
->SetDrawingMode(B_OP_OVER
);
435 if (IsActivePrinter()) {
436 if (sSelectedIcon
&& sSelectedIcon
->IsValid())
437 owner
->DrawBitmap(sSelectedIcon
, iconPt
);
439 owner
->DrawString(B_TRANSLATE("Default Printer"), defaultPt
);
441 if (sIcon
&& sIcon
->IsValid())
442 owner
->DrawBitmap(sIcon
, iconPt
);
445 owner
->SetDrawingMode(B_OP_OVER
);
449 owner
->SetFont(be_bold_font
);
450 owner
->TruncateString(&s
, B_TRUNCATE_MIDDLE
, pendingPt
.x
- namePt
.x
);
451 owner
->DrawString(s
.String(), s
.Length(), namePt
);
452 owner
->SetFont(&font
);
454 s
= B_TRANSLATE("Driver: %driver%");
455 s
.ReplaceFirst("%driver%", fDriverName
);
456 owner
->TruncateString(&s
, B_TRUNCATE_END
, commentPt
.x
- driverPt
.x
);
457 owner
->DrawString(s
.String(), s
.Length(), driverPt
);
460 if (fTransport
.Length() > 0) {
461 s
= B_TRANSLATE("Transport: %transport% %transport_address%");
462 s
.ReplaceFirst("%transport%", fTransport
);
463 s
.ReplaceFirst("%transport_address%", fTransportAddress
);
464 owner
->TruncateString(&s
, B_TRUNCATE_BEGINNING
, totalWidth
);
465 owner
->DrawString(s
.String(), s
.Length(), transportPt
);
470 owner
->TruncateString(&s
, B_TRUNCATE_END
, bounds
.Width() - pendingPt
.x
);
471 owner
->DrawString(s
.String(), s
.Length(), pendingPt
);
474 owner
->TruncateString(&s
, B_TRUNCATE_MIDDLE
, bounds
.Width() - commentPt
.x
);
475 owner
->DrawString(s
.String(), s
.Length(), commentPt
);
477 owner
->SetDrawingMode(mode
);
482 PrinterItem::IsActivePrinter() const
484 return fName
== ActivePrinterName();
489 PrinterItem::HasPendingJobs() const
491 return fFolder
&& fFolder
->CountJobs() > 0;
496 PrinterItem::Folder() const
510 PrinterItem::UpdatePendingJobs()
513 uint32 pendingJobs
= fFolder
->CountJobs();
514 if (pendingJobs
== 1) {
515 fPendingJobs
= B_TRANSLATE("1 pending job.");
517 } else if (pendingJobs
> 1) {
519 fPendingJobs
<< pendingJobs
<< B_TRANSLATE(" pending jobs.");
523 fPendingJobs
= B_TRANSLATE("No pending jobs.");
528 PrinterItem::_GetStringProperty(const char* propName
, BString
& outString
)
530 fNode
.ReadAttrString(propName
, &outString
);
535 PrinterItem::_LoadVectorIcon(const char* resourceName
, float iconSize
)
538 BResources
* resources
= BApplication::AppResources();
539 const void* data
= resources
->LoadResource(B_VECTOR_ICON_TYPE
,
540 resourceName
, &dataSize
);
543 BBitmap
*iconBitmap
= new BBitmap(BRect(0, 0, iconSize
- 1,
544 iconSize
- 1), 0, B_RGBA32
);
545 if (BIconUtils::GetVectorIcon(
546 reinterpret_cast<const uint8
*>(data
),
547 dataSize
, iconBitmap
) == B_OK
)