#include "CtrlLib.h" #ifdef GUI_WIN #ifndef PLATFORM_WINCE #include #pragma comment(lib, "comdlg32.lib") #endif #else #include #endif NAMESPACE_UPP #ifdef GUI_WIN #ifndef PLATFORM_WINCE #include #pragma comment(lib, "comdlg32.lib") struct Win32PrintDlg_ : PRINTDLG { Win32PrintDlg_() { memset(this, 0, sizeof(PRINTDLG)); lStructSize = sizeof(PRINTDLG); } ~Win32PrintDlg_() { if(hDevMode) ::GlobalFree(hDevMode); if(hDevNames) ::GlobalFree(hDevNames); } }; PrinterJob::PrinterJob(const char *_name) { name = _name; landscape = false; from = to = 1; current = 1; } PrinterJob::~PrinterJob() { } bool PrinterJob::Execute0(bool dodlg) { pdlg = new Win32PrintDlg_; PRINTDLG& dlg = *pdlg; dlg.Flags = PD_DISABLEPRINTTOFILE|PD_NOSELECTION|PD_HIDEPRINTTOFILE|PD_RETURNDEFAULT; dlg.nFromPage = current; dlg.nToPage = current; dlg.nMinPage = from; dlg.nMaxPage = to; if(from != to) dlg.Flags |= PD_ALLPAGES; dlg.hwndOwner = 0; dlg.Flags |= PD_RETURNDEFAULT; dlg.nCopies = 1; if(!PrintDlg(&dlg)) return false; if(dlg.hDevMode) { DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(dlg.hDevMode); pDevMode->dmOrientation = landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; ::GlobalUnlock(dlg.hDevMode); } HDC hdc; if(dodlg) { dlg.Flags = PD_DISABLEPRINTTOFILE|PD_NOSELECTION|PD_HIDEPRINTTOFILE|PD_RETURNDC; Vector< Ptr > disabled = DisableCtrls(Ctrl::GetTopCtrls()); bool b = PrintDlg(&dlg); EnableCtrls(disabled); if(!b) return false; hdc = dlg.hDC; } else { DEVNAMES *p = (DEVNAMES *)::GlobalLock(dlg.hDevNames); const char *driver = (const char *)p + p->wDriverOffset; const char *device = (const char *)p + p->wDeviceOffset; if(dlg.hDevMode) { DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(dlg.hDevMode); hdc = CreateDC(driver, device, NULL, pDevMode); ::GlobalUnlock(dlg.hDevMode); } else hdc = CreateDC(driver, device, NULL, NULL); } if(dlg.hDevMode) ::GlobalFree(dlg.hDevMode); if(dlg.hDevNames) ::GlobalFree(dlg.hDevNames); if(hdc) { draw = new PrintDraw(hdc, Nvl(name, Ctrl::GetAppName())); page.Clear(); if(!(dlg.Flags & PD_PAGENUMS)) { dlg.nFromPage = dlg.nMinPage; dlg.nToPage = dlg.nMaxPage; } for(int c = 0; c < ((dlg.Flags & PD_COLLATE) ? dlg.nCopies : 1); c++) for(int i = dlg.nFromPage - 1; i <= dlg.nToPage - 1; i++) for(int c = 0; c < ((dlg.Flags & PD_COLLATE) ? 1 : dlg.nCopies); c++) page.Add(i); return true; } return false; } bool PrinterJob::Execute() { return Execute0(true); } Draw& PrinterJob::GetDraw() { if(!draw) { Execute0(false); if(!draw) draw = new NilDraw; } return *draw; } PrinterJob& PrinterJob::MinMaxPage(int minpage, int maxpage) { from = minpage + 1; to = maxpage + 1; return *this; } PrinterJob& PrinterJob::CurrentPage(int i) { current = i + 1; return *this; } #endif #endif #ifdef PLATFORM_X11 struct PageSizeName { const char *name; int cx, cy; Size GetDots() const { return Size(6000 * cx / 254, 6000 * cy / 254); } } static const PageName2Size[] = { { "A0", 841, 1189 }, { "A1", 594, 841 }, { "A2", 420, 594 }, { "A3", 297, 420 }, { "A4", 210, 297 }, { "A5", 148, 210 }, { "A6", 105, 148 }, { "A7", 74, 105 }, { "A8", 52, 74 }, { "A9", 37, 52 }, { "B0", 1030, 1456 }, { "B1", 728, 1030 }, { "B10", 32, 45 }, { "B2", 515, 728 }, { "B3", 364, 515 }, { "B4", 257, 364 }, { "B5", 182, 257 }, { "B6", 128, 182 }, { "B7", 91, 128 }, { "B8", 64, 91 }, { "B9", 45, 64 }, { "C5E", 163, 229 }, { "Comm10E", 105, 241 }, { "DLE", 110, 220 }, { "Executive", 191, 254 }, { "Folio", 210, 330 }, { "Ledger", 432, 279 }, { "Legal", 216, 356 }, { "Letter", 216, 279 }, { "Tabloid", 279, 432 } }; const PageSizeName *FindPageSize(const String& name) { for(int i = 0; i < __countof(PageName2Size); i++) if(PageName2Size[i].name == name) return &PageName2Size[i]; return NULL; } String System(const char *cmd, const String& in) { String ofn = GetTempFileName(); String ifn = GetTempFileName(); SaveFile(ifn, in); String c = cmd; c << " >" << ofn; if(in.GetCount()) c << " <" << ifn; String q; if(system(c) >= 0) q = LoadFile(ofn); FileDelete(ofn); FileDelete(ifn); return q; } String System(const char *cmd) { return System(cmd, Null); } class PrinterDlg : public WithPrinterLayout { typedef PrinterDlg CLASSNAME; public: void FillOpt(const String& s, const char *id, DropList& dl, bool pgsz); void SyncPrinterOptions(); PrinterDlg(); bool IsCanceled(); private: void OnOK(); private: bool canceled; }; void PrinterDlg::FillOpt(const String& s, const char *id, DropList& dl, bool pgsz) { int a = s.Find('/'); int b = s.Find(':'); if(a > 0 && b > a) { String opt = ToLower(s.Mid(0, a)); if(opt == id) { Vector v = Split(~s + b + 1, ' '); dl.Enable(); for(int i = 0; i < v.GetCount(); i++) { String o = v[i]; if(o[0] == '*') { o = o.Mid(1); dl <<= o; } if(!pgsz || FindPageSize(o)) dl.Add(o); } } } } void PrinterDlg::SyncPrinterOptions() { Vector l = Split(System("lpoptions -l -d " + String(~printer)), '\n'); paper.Disable(); paper.Clear(); slot.Disable(); slot.Clear(); for(int i = 0; i < l.GetCount(); i++) { FillOpt(l[i], "pagesize", paper, true); FillOpt(l[i], "inputslot", slot, false); } } PrinterDlg::PrinterDlg() : canceled(true) { CtrlLayoutOKCancel(*this, "Print"); printer <<= THISBACK(SyncPrinterOptions); ok <<= THISBACK(OnOK); npage.Add(1); npage.Add(2); npage.Add(4); npage.Add(6); npage.Add(9); npage.Add(16); npage <<= 1; copies <<= 1; landscape <<= 0; range <<= 0; Vector l = Split(System("lpstat -a"), '\n'); for(int i = 0; i < l.GetCount(); i++) { Vector w = Split(l[i], ' '); if(w.GetCount()) printer.Add(w[0]); } String h = System("lpstat -d"); int q = h.Find(':'); if(q >= 0) { String p = h.Mid(q + 1); if(printer.HasKey(p)) { printer <<= p; SyncPrinterOptions(); return; } } if(printer.GetCount()) { printer.SetIndex(0); SyncPrinterOptions(); } } bool PrinterDlg::IsCanceled() { return canceled; } void PrinterDlg::OnOK() { canceled = false; Close(); } Size PrinterJob::GetDefaultPageSize(String *name) { static const char PageSize[] = "Page Size:"; Size sz(6000 * 210 / 254, 6000 * 297 / 254); //default printer properties Vector dpp = Split(System("lpoptions -l"), '\n'); for (int i = 0; i < dpp.GetCount(); i++){ int pos = dpp[i].Find(PageSize); if (pos >= 0){ pos += sizeof(PageSize); pos = dpp[i].Find('*', pos); //return A4 if there is not default page size if (pos < 0) return sz; //skip '*' pos++; int len = dpp[i].Find(' ', pos); if (len < 0) len = dpp[i].GetLength(); len -= pos; //page name String nm = dpp[i].Mid(pos, len); if(name) *name = nm; const PageSizeName *p = FindPageSize(nm); if(p) { sz = p->GetDots(); return sz; } } } //return A4 if there is not default page size return sz; } PrinterJob::PrinterJob(const char *_name) { name = _name; landscape = false; from = to = 0; current = 0; pgsz = GetDefaultPageSize(); } PrinterJob::~PrinterJob() { } bool PrinterJob::Execute0(bool dodlg) { PrinterDlg dlg; dlg.from <<= from + 1; dlg.to <<= to + 1; dlg.from.Min(from + 1).Max(to + 1); dlg.to.Min(from + 1).Max(to + 1); dlg.from.Enable(from != to); dlg.to.Enable(from != to); dlg.range.EnableCase(1, from != to); dlg.range.EnableCase(2, from != to); String h; GetDefaultPageSize(&h); h.IsEmpty() ? dlg.paper <<= "A4" : dlg.paper <<= h; if(dodlg) { dlg.Run(); if (!dlg.IsCanceled()) return false; } options.Clear(); options << "-d " << ~dlg.printer; options << " -o media="; dlg.paper.GetIndex() < 0 ? options << ~dlg.slot : options << ~dlg.paper << "," << ~dlg.slot; if(dlg.landscape) options << " -o landscape"; options << " -o number-up=" << ~dlg.npage; options << " -n " << ~dlg.copies; if(dlg.collate) options << " -o Collate=True"; page.Clear(); switch(dlg.range) { case 0: for(int i = from; i <= to; i++) page.Add(i); break; case 1: page.Add(current); break; case 2: for(int i = (int)~dlg.from - 1; i <= (int)~dlg.to - 1; i++) page.Add(i); break; } pgsz = Size(5100, 6600); const PageSizeName *p = FindPageSize(~dlg.paper); if(p) pgsz = p->GetDots(); return true; } bool PrinterJob::Execute() { return Execute0(false); } struct PrinterDraw : PdfDraw { String options; bool canceled; PrinterDraw(Size sz) : PdfDraw(sz), canceled(true) {} ~PrinterDraw() { if(!canceled && !IsEmpty()) { System("lp " + options, Finish()); } } }; Draw& PrinterJob::GetDraw() { if(!draw) { bool canceled = Execute0(true); PrinterDraw *pd = new PrinterDraw(pgsz); pd->canceled = canceled; pd->options = options; draw = pd; } return *draw; } PrinterJob& PrinterJob::MinMaxPage(int minpage, int maxpage) { from = minpage; to = maxpage; return *this; } PrinterJob& PrinterJob::CurrentPage(int i) { current = i; return *this; } #endif END_UPP_NAMESPACE