1 /* 2 * Copyright 2002-2008, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Pfeiffer 7 */ 8 9 #include "pr_server.h" 10 #include "Printer.h" 11 #include "PrintServerApp.h" 12 #include "ConfigWindow.h" 13 #include "PrintUtils.h" 14 15 // posix 16 #include <limits.h> 17 #include <math.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 // BeOS 22 #include <Application.h> 23 #include <Autolock.h> 24 #include <Window.h> 25 26 27 static const float a0_width = 2380.0; 28 static const float a0_height = 3368.0; 29 static const float a1_width = 1684.0; 30 static const float a1_height = 2380.0; 31 static const float a2_width = 1190.0; 32 static const float a2_height = 1684.0; 33 static const float a3_width = 842.0; 34 static const float a3_height = 1190.0; 35 static const float a4_width = 595.0; 36 static const float a4_height = 842.0; 37 static const float a5_width = 421.0; 38 static const float a5_height = 595.0; 39 static const float a6_width = 297.0; 40 static const float a6_height = 421.0; 41 static const float b5_width = 501.0; 42 static const float b5_height = 709.0; 43 static const float letter_width = 612.0; 44 static const float letter_height = 792.0; 45 static const float legal_width = 612.0; 46 static const float legal_height = 1008.0; 47 static const float ledger_width = 1224.0; 48 static const float ledger_height = 792.0; 49 static const float p11x17_width = 792.0; 50 static const float p11x17_height = 1224.0; 51 52 53 static struct PageFormat 54 { 55 char *label; 56 float width; 57 float height; 58 } pageFormat[] = 59 { 60 {"Letter", letter_width, letter_height }, 61 {"Legal", legal_width, legal_height }, 62 {"Ledger", ledger_width, ledger_height }, 63 {"p11x17", p11x17_width, p11x17_height }, 64 {"A0", a0_width, a0_height }, 65 {"A1", a1_width, a1_height }, 66 {"A2", a2_width, a2_height }, 67 {"A3", a3_width, a3_height }, 68 {"A4", a4_width, a4_height }, 69 {"A5", a5_width, a5_height }, 70 {"A6", a6_width, a6_height }, 71 {"B5", b5_width, b5_height }, 72 }; 73 74 75 static void GetPageFormat(float w, float h, BString& label) 76 { 77 w = floor(w + 0.5); h = floor(h + 0.5); 78 for (uint i = 0; i < sizeof(pageFormat) / sizeof(struct PageFormat); i ++) { 79 struct PageFormat& pf = pageFormat[i]; 80 if (pf.width == w && pf.height == h || pf.width == h && pf.height == w) { 81 label = pf.label; return; 82 } 83 } 84 85 float unit = 72.0; // currently inc[h]es only 86 label << (w / unit) << "x" << (h / unit) << " in."; 87 } 88 89 90 ConfigWindow::ConfigWindow(config_setup_kind kind, Printer* defaultPrinter, 91 BMessage* settings, AutoReply* sender) 92 : BWindow(ConfigWindow::GetWindowFrame(), "Page Setup", 93 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) 94 , fKind(kind) 95 , fDefaultPrinter(defaultPrinter) 96 , fSettings(settings) 97 , fSender(sender) 98 , fCurrentPrinter(NULL) 99 , fPageFormatText(NULL) 100 , fJobSetupText(NULL) 101 { 102 MimeTypeForSender(settings, fSenderMimeType); 103 PrinterForMimeType(); 104 105 if (kind == kJobSetup) 106 SetTitle("Print Setup"); 107 108 BView* panel = new BBox(Bounds(), "top_panel", B_FOLLOW_ALL, 109 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, 110 B_PLAIN_BORDER); 111 112 AddChild(panel); 113 114 float left = 10, top = 10; 115 BRect r(left, top, 160, 20); 116 117 // print selection popup menu 118 BPopUpMenu* menu = new BPopUpMenu("Select a Printer"); 119 SetupPrintersMenu(menu); 120 121 float width = be_plain_font->StringWidth("Printer:") + 10.0; 122 r.right = r.left + width + menu->MaxContentWidth() + 10; 123 fPrinters = new BMenuField(r, "Printer", "Printer:", menu); 124 fPrinters->SetDivider(width); 125 panel->AddChild(fPrinters); 126 top += fPrinters->Bounds().Height() + 10; 127 128 // page format button 129 r.OffsetTo(left, top); 130 fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON", 131 "PAGE_SETUP_OFF", MSG_PAGE_SETUP); 132 133 // add description to button 134 r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, fPageSetup->Frame().top); 135 BStringView *stringView = AddStringView(panel, r, "Paper Setup:"); 136 stringView->ResizeToPreferred(); 137 r = stringView->Frame(); 138 r.OffsetBy(0, r.Height()); 139 fPageFormatText = AddStringView(panel, r, ""); 140 fPageFormatText->ResizeToPreferred(); 141 top = fPageSetup->Frame().bottom + 15; 142 143 // page selection button 144 fJobSetup = NULL; 145 if (kind == kJobSetup) { 146 r.OffsetTo(left, top); 147 fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON", 148 "JOB_SETUP_OFF", MSG_JOB_SETUP); 149 // add description to button 150 r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top); 151 stringView = AddStringView(panel, r, "Pages to Print:"); 152 stringView->ResizeToPreferred(); 153 r.OffsetBy(0, stringView->Frame().Height()); 154 fJobSetupText = AddStringView(panel, r, ""); 155 fJobSetupText->ResizeToPreferred(); 156 top = fJobSetup->Frame().bottom + 15; 157 } 158 top += 5; 159 160 // separator line 161 BRect line(Bounds()); 162 line.OffsetTo(0, top); 163 line.bottom = line.top+1; 164 AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP)); 165 top += 10; 166 167 // Cancel button 168 r.OffsetTo(left, top); 169 BButton* cancel = new BButton(r, "Cancel", "Cancel", 170 new BMessage(B_QUIT_REQUESTED)); 171 panel->AddChild(cancel); 172 cancel->ResizeToPreferred(); 173 left = cancel->Frame().right + 10; 174 175 // OK button 176 r.OffsetTo(left, top); 177 fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK)); 178 panel->AddChild(fOk); 179 fOk->ResizeToPreferred(); 180 top += fOk->Bounds().Height() + 10; 181 182 // resize window 183 ResizeTo(fOk->Frame().right + 10, top); 184 185 AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED)); 186 187 SetDefaultButton(fOk); 188 189 fPrinters->MakeFocus(true); 190 191 UpdateSettings(true); 192 } 193 194 ConfigWindow::~ConfigWindow() 195 { 196 if (fCurrentPrinter) 197 fCurrentPrinter->Release(); 198 release_sem(fFinished); 199 } 200 201 202 void ConfigWindow::Go() 203 { 204 sem_id sid = create_sem(0, "finished"); 205 if (sid >= 0) { 206 fFinished = sid; 207 Show(); 208 acquire_sem(sid); 209 delete_sem(sid); 210 } else { 211 Quit(); 212 } 213 } 214 215 216 void ConfigWindow::MessageReceived(BMessage* m) 217 { 218 switch (m->what) { 219 case MSG_PAGE_SETUP: 220 Setup(kPageSetup); 221 break; 222 case MSG_JOB_SETUP: 223 Setup(kJobSetup); 224 break; 225 case MSG_PRINTER_SELECTED: { 226 BString printer; 227 if (m->FindString("name", &printer) == B_OK) { 228 UpdateAppSettings(fSenderMimeType.String(), printer.String()); 229 PrinterForMimeType(); 230 UpdateSettings(true); 231 } 232 } 233 break; 234 case MSG_OK: 235 UpdateSettings(false); 236 fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings); 237 Quit(); 238 break; 239 case B_ABOUT_REQUESTED: AboutRequested(); 240 break; 241 default: 242 BWindow::MessageReceived(m); 243 } 244 } 245 246 247 static const char* 248 kAbout = 249 "Printer Server\n" 250 "© 2001-2008 Haiku\n" 251 "\n" 252 "\tIthamar R. Adema - Initial Implementation\n" 253 "\tMichael Pfeiffer - Release 1 and beyond\n" 254 ; 255 256 257 void 258 ConfigWindow::AboutRequested() 259 { 260 BAlert *about = new BAlert("About Printer Server", kAbout, "OK"); 261 about->Go(); 262 } 263 264 265 void ConfigWindow::FrameMoved(BPoint p) 266 { 267 BRect frame = GetWindowFrame(); 268 frame.OffsetTo(p); 269 SetWindowFrame(frame); 270 } 271 272 273 BRect ConfigWindow::GetWindowFrame() 274 { 275 BAutolock lock(gLock); 276 if (lock.IsLocked()) 277 return Settings::GetSettings()->ConfigWindowFrame(); 278 279 return BRect(30, 30, 300, 300); 280 } 281 282 283 void ConfigWindow::SetWindowFrame(BRect r) 284 { 285 BAutolock lock(gLock); 286 if (lock.IsLocked()) 287 Settings::GetSettings()->SetConfigWindowFrame(r); 288 } 289 290 291 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame, 292 const char* name, const char* on, const char* off, uint32 what) 293 { 294 BBitmap* onBM = LoadBitmap(on); 295 BBitmap* offBM = LoadBitmap(off); 296 297 BPicture* onPict = BitmapToPicture(panel, onBM); 298 BPicture* offPict = BitmapToPicture(panel, offBM); 299 300 BPictureButton* button = NULL; 301 302 if (onPict != NULL && offPict != NULL) { 303 button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what)); 304 button->SetViewColor(B_TRANSPARENT_COLOR); 305 panel->AddChild(button); 306 onBM->Lock(); 307 button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height()); 308 onBM->Unlock(); 309 310 BPicture* disabled = BitmapToGrayedPicture(panel, offBM); 311 button->SetDisabledOn(disabled); 312 delete disabled; 313 314 disabled = BitmapToGrayedPicture(panel, onBM); 315 button->SetDisabledOff(disabled); 316 delete disabled; 317 } 318 319 delete onPict; delete offPict; 320 delete onBM; delete offBM; 321 322 return button; 323 } 324 325 326 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text) 327 { 328 // frame.bottom = frame.top ; 329 BStringView* string = new BStringView(frame, "", text); 330 string->SetViewColor(panel->ViewColor()); 331 string->SetLowColor(panel->ViewColor()); 332 panel->AddChild(string); 333 return string; 334 } 335 336 337 void ConfigWindow::PrinterForMimeType() 338 { 339 BAutolock lock(gLock); 340 if (fCurrentPrinter) { 341 fCurrentPrinter->Release(); 342 fCurrentPrinter = NULL; 343 } 344 345 if (lock.IsLocked()) { 346 Settings* s = Settings::GetSettings(); 347 AppSettings* app = s->FindAppSettings(fSenderMimeType.String()); 348 if (app) { 349 fPrinterName = app->GetPrinter(); 350 } else { 351 fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : ""; 352 } 353 fCurrentPrinter = Printer::Find(fPrinterName); 354 if (fCurrentPrinter) 355 fCurrentPrinter->Acquire(); 356 } 357 } 358 359 360 void ConfigWindow::SetupPrintersMenu(BMenu* menu) 361 { 362 // clear menu 363 while (menu->CountItems() != 0) 364 delete menu->RemoveItem(0L); 365 366 // fill menu with printer names 367 BAutolock lock(gLock); 368 if (lock.IsLocked()) { 369 BString n; 370 BMessage* m; 371 BMenuItem* item; 372 for (int i = 0; i < Printer::CountPrinters(); i ++) { 373 Printer::At(i)->GetName(n); 374 m = new BMessage(MSG_PRINTER_SELECTED); 375 m->AddString("name", n.String()); 376 menu->AddItem(item = new BMenuItem(n.String(), m)); 377 if (n == fPrinterName) 378 item->SetMarked(true); 379 } 380 } 381 } 382 383 384 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer) 385 { 386 BAutolock lock(gLock); 387 if (lock.IsLocked()) { 388 Settings* s = Settings::GetSettings(); 389 AppSettings* app = s->FindAppSettings(mime); 390 if (app) 391 app->SetPrinter(printer); 392 else 393 s->AddAppSettings(new AppSettings(mime, printer)); 394 } 395 } 396 397 398 void ConfigWindow::UpdateSettings(bool read) 399 { 400 BAutolock lock(gLock); 401 if (lock.IsLocked()) { 402 Settings* s = Settings::GetSettings(); 403 PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String()); 404 if (p == NULL) { 405 p = new PrinterSettings(fPrinterName.String()); 406 s->AddPrinterSettings(p); 407 } 408 ASSERT(p != NULL); 409 if (read) { 410 fPageSettings = *p->GetPageSettings(); 411 fJobSettings = *p->GetJobSettings(); 412 } else { 413 p->SetPageSettings(&fPageSettings); 414 p->SetJobSettings(&fJobSettings); 415 } 416 } 417 UpdateUI(); 418 } 419 420 421 void ConfigWindow::UpdateUI() 422 { 423 if (fCurrentPrinter == NULL) { 424 fPageSetup->SetEnabled(false); 425 if (fJobSetup) { 426 fJobSetup->SetEnabled(false); 427 fJobSetupText->SetText("Undefined job settings"); 428 fJobSetupText->ResizeToPreferred(); 429 } 430 fOk->SetEnabled(false); 431 fPageFormatText->SetText("Undefined paper format"); 432 fPageFormatText->ResizeToPreferred(); 433 } else { 434 fPageSetup->SetEnabled(true); 435 436 if (fJobSetup) 437 fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty()); 438 439 fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() || 440 fKind == kPageSetup && !fPageSettings.IsEmpty()); 441 442 // display information about page format 443 BRect paperRect; 444 BString pageFormat; 445 if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) { 446 GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat); 447 448 int32 orientation = 0; 449 fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation); 450 if (orientation == 0) 451 pageFormat << ", Portrait"; 452 else 453 pageFormat << ", Landscape"; 454 } else { 455 pageFormat << "Undefined paper format"; 456 } 457 fPageFormatText->SetText(pageFormat.String()); 458 fPageFormatText->ResizeToPreferred(); 459 460 // display information about job 461 if (fKind == kJobSetup) { 462 BString job; 463 int32 first, last; 464 if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK && 465 fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) { 466 if (first >= 1 && first <= last && last != INT_MAX) { 467 job << "From page " << first << " to " << last; 468 } else { 469 job << "All pages"; 470 } 471 int32 copies; 472 if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies) 473 == B_OK && copies > 1) { 474 job << ", " << copies << " copies"; 475 } 476 } else { 477 job << "Undefined job settings"; 478 } 479 fJobSetupText->SetText(job.String()); 480 fJobSetupText->ResizeToPreferred(); 481 } 482 } 483 484 if (fOk->Frame().right < fPageFormatText->Frame().right) 485 ResizeTo(fPageFormatText->Frame().right + 10, Bounds().bottom); 486 487 if (fJobSetupText) { 488 if (fOk->Frame().right < fJobSetupText->Frame().right) 489 ResizeTo(fJobSetupText->Frame().right + 10, Bounds().bottom); 490 } 491 } 492 493 494 void ConfigWindow::Setup(config_setup_kind kind) 495 { 496 if (fCurrentPrinter) { 497 Hide(); 498 if (kind == kPageSetup) { 499 BMessage settings = fPageSettings; 500 if (fCurrentPrinter->ConfigurePage(settings) == B_OK) { 501 fPageSettings = settings; 502 if (!fJobSettings.IsEmpty()) 503 AddFields(&fJobSettings, &fPageSettings); 504 } 505 } else { 506 BMessage settings; 507 if (fJobSettings.IsEmpty()) settings = fPageSettings; 508 else settings = fJobSettings; 509 510 if (fCurrentPrinter->ConfigureJob(settings) == B_OK) 511 fJobSettings = settings; 512 } 513 UpdateUI(); 514 Show(); 515 } 516 } 517