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