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