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