/* $Id$ Copyright (C) 1997 Bernd Johannes Wuebben wuebben@math.cornell.edu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef KDE_USE_FINAL /* NewImage() in viewfax.cpp needs to fiddle with the Display structure */ #define XLIB_ILLEGAL_ACCESS #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "faxexpand.h" #include "kfax.h" #include "version.h" #include "viewfax.h" #include "options.h" #include "kfax_printsettings.h" #include #include #include #include #include #include #include #include // StatusBar field IDs #define ID_LINE_COLUMN 1 #define ID_INS_OVR 2 #define ID_GENERAL 3 #define ID_FNAME 4 #define ID_TYPE 5 #define ID_PAGE_NO 6 TopLevel *toplevel; extern int GetImage(struct pagenode *pn); void TurnFollowing(int How, struct pagenode *pn); void handle_X_event(XEvent event); void ShowLoop(void); void SetupDisplay(); void mysighandler(int sig); void setFaxDefaults(); void parse(char* buf, char** args); extern void g31expand(struct pagenode *pn, drawfunc df); extern void g32expand(struct pagenode *pn, drawfunc df); extern void g4expand(struct pagenode *pn, drawfunc df); #define PATIENCE 100000 static char KFAX_FILETYPES[] = "image/fax-g3 image/tiff"; int ExpectConfNotify = 1; GC PaintGC; Cursor WorkCursor; Cursor ReadyCursor; Cursor MoveCursor; Cursor LRCursor; Cursor UDCursor; extern Time Lasttime; extern bool have_cmd_opt; extern struct pagenode *viewpage; extern XImage *FlipImage(XImage *xi); extern XImage *MirrorImage(XImage *xi); extern XImage *RotImage(XImage *Image); extern XImage *ZoomImage(XImage *Big); extern void FreeImage(XImage *Image); extern XImage *Image, *Images[MAXZOOM]; int xpos, ox; /* x, old x, offset x, new xpos*/ int ypos, oy; /* y, old y, offset y, new y */ int offx, offy; int nx, ny; int oz, Resize, Refresh; /* old zoom, window size changed, needs updating */ int PaneWidth, PaneHeight; /* current size of our window */ int AbsX, AbsY; /* absolute position of centre of window */ Display* qtdisplay; int startingup; Window qtwin; // the qt window Window Win; int qwindow_height; int qwindow_width; bool have_no_fax = TRUE; bool display_is_setup = FALSE; struct optionsinfo fop; // contains the fax options extern struct pagenode *firstpage, *lastpage, *thispage; extern struct pagenode* auxpage; extern struct pagenode defaultpage; bool buttondown; bool MyApp::x11EventFilter( XEvent * ev) { if (TDEApplication::x11EventFilter(ev)) return TRUE; if (ev->type == ButtonRelease){ /* this is so that the cursor goes back to normal on leaving the fax window and that the fax won't be moved when I reenter after I release the mouse*/ if (buttondown == true){ buttondown = false; XDefineCursor(qtdisplay, Win, ReadyCursor); XFlush(qtdisplay); } } if ( ev->xany.window == qtwin || ev->xany.window == Win){ if(startingup || have_no_fax) return FALSE; toplevel->handle_X_event(*ev); ev->xany.window = qtwin; } return FALSE; } TopLevel::TopLevel (TQWidget *, const char *name) : KMainWindow (0, name) { setMinimumSize (100, 100); buttondown = false; setupMenuBar(); setupStatusBar(); updateActions(); resize(550,400); setupGUI(); readSettings(); faxqtwin = new TQFrame(this); qtwin = faxqtwin->winId(); faxqtwin->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); // Create aQt::Vertical scroll bar vsb = new TQScrollBar( Qt::Vertical,faxqtwin,"scrollBar" ); vsb->hide(); connect( vsb, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(scrollVert(int)) ); // Create aQt::Horizontal scroll bar hsb = new TQScrollBar( Qt::Horizontal,faxqtwin,"scrollBar" ); connect( hsb, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(scrollHorz(int)) ); hsb->hide(); setCentralWidget(faxqtwin); setAcceptDrops(true); show(); } TopLevel::~TopLevel() { } void TopLevel::setupMenuBar() { // File menu KStdAction::open( TQT_TQOBJECT(this), TQT_SLOT( faxOpen() ), actionCollection() ); actRecent = KStdAction::openRecent( TQT_TQOBJECT(this), TQT_SLOT( faxOpen( const KURL & ) ), actionCollection() ); actSave = KStdAction::save( TQT_TQOBJECT(this), TQT_SLOT( faxSave() ), actionCollection() ); actSaveAs = KStdAction::saveAs( TQT_TQOBJECT(this), TQT_SLOT( faxSaveAs() ), actionCollection() ); actPrint = KStdAction::print( TQT_TQOBJECT(this), TQT_SLOT( print() ), actionCollection() ); KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( close() ), actionCollection() ); actAdd = new KAction( i18n( "A&dd..." ), "filenew", KShortcut(), TQT_TQOBJECT(this), TQT_SLOT( faxAdd() ), actionCollection(), "file_add_fax" ); actRecent->setMaxItems( 5 ); // View Menu actSize = KStdAction::actualSize( TQT_TQOBJECT(this), TQT_SLOT( actualSize() ), actionCollection() ); actZoomIn = KStdAction::zoomIn( TQT_TQOBJECT(this), TQT_SLOT( zoomin() ), actionCollection() ); actZoomOut = KStdAction::zoomOut( TQT_TQOBJECT(this), TQT_SLOT( zoomout() ), actionCollection() ); actRotate = new KAction( i18n( "&Rotate Page" ), "rotate", KShortcut(), TQT_TQOBJECT(this), TQT_SLOT( rotatePage() ), actionCollection(), "view_rotate" ); actMirror = new KAction( i18n( "Mirror Page" ), KShortcut(), TQT_TQOBJECT(this), TQT_SLOT( mirrorPage() ), actionCollection(), "view_mirror" ); actFlip = new KAction( i18n( "&Flip Page" ), KShortcut(), TQT_TQOBJECT(this), TQT_SLOT( flipPage() ), actionCollection(), "view_flip" ); // Go menu actNext = KStdAction::next( TQT_TQOBJECT(this), TQT_SLOT( nextPage() ), actionCollection() ); actPrev = KStdAction::prior( TQT_TQOBJECT(this), TQT_SLOT( prevPage() ), actionCollection() ); actFirst = KStdAction::firstPage( TQT_TQOBJECT(this), TQT_SLOT( firstPage() ), actionCollection() ); actLast = KStdAction::lastPage( TQT_TQOBJECT(this), TQT_SLOT( lastPage() ), actionCollection() ); // Settings menu KStdAction::preferences( TQT_TQOBJECT(this), TQT_SLOT( faxoptions() ), actionCollection() ); } void TopLevel::setupStatusBar() { statusbar = statusBar(); statusbar->insertFixedItem(i18n("w: 00000 h: 00000"), ID_INS_OVR); statusbar->insertFixedItem(i18n("Res: XXXXX"), ID_GENERAL); statusbar->insertFixedItem(i18n("Type: XXXXXXX"), ID_TYPE); statusbar->insertFixedItem(i18n("Page: XX of XX"), ID_PAGE_NO); statusbar->insertItem(TQString(), ID_FNAME, 1); statusbar->setItemAlignment( ID_FNAME, AlignLeft ); statusbar->changeItem(TQString(), ID_INS_OVR); statusbar->changeItem(TQString(), ID_GENERAL); statusbar->changeItem(TQString(), ID_TYPE); statusbar->changeItem(TQString(), ID_PAGE_NO); statusbar->changeItem(TQString(), ID_FNAME); } void TopLevel::readSettings() { config = kapp->config(); applyMainWindowSettings( config, "MainWindowSettings" ); actRecent->loadEntries( config ); config->setGroup("General Options"); config->setGroup("Fax Options"); fop.width = config->readNumEntry("width", 1728); fop.resauto = config->readNumEntry("resauto", 1); fop.geomauto = config->readNumEntry("geomauto", 1); fop.height = config->readNumEntry("height", 2339); fop.fine = config->readNumEntry("resolution", 1); fop.flip = config->readNumEntry("flip", 0); fop.invert = config->readNumEntry("invert", 0); fop.lsbfirst = config->readNumEntry("lsb", 0); fop.raw = config->readNumEntry("raw", 3); setFaxDefaults(); } void TopLevel::updateActions() { actAdd->setEnabled( thispage ); actSave->setEnabled( thispage ); actSaveAs->setEnabled( thispage ); actPrint->setEnabled( thispage ); actRotate->setEnabled( thispage ); actFlip->setEnabled( thispage ); actMirror->setEnabled( thispage ); updateGoActions(); updateZoomActions(); } void TopLevel::updateGoActions() { actNext->setEnabled( thispage && thispage->next ); actPrev->setEnabled( thispage && thispage->prev ); actFirst->setEnabled( thispage && thispage->prev ); actLast->setEnabled( thispage && thispage->next ); } void TopLevel::updateZoomActions() { actSize->setEnabled( Image && oz > 0 ); actZoomIn->setEnabled( Image && oz > 0 ); actZoomOut->setEnabled( Image && oz < MAXZOOM-1 && Image->width >= 256 ); } bool TopLevel::queryClose() { saveMainWindowSettings( config, "MainWindowSettings" ); actRecent->saveEntries( config ); return true; } void TopLevel::writeSettings() { config = kapp->config(); config->setGroup("General Options"); config->setGroup("Fax Options"); config->writeEntry("resauto",fop.resauto); config->writeEntry("geomauto",fop.geomauto); config->writeEntry("width",fop.width); config->writeEntry("height",fop.height); config->writeEntry("resolution",fop.fine); config->writeEntry("flip",fop.flip); config->writeEntry("invert",fop.invert); config->writeEntry("lsb",fop.lsbfirst); config->writeEntry("raw",fop.raw); config->sync(); } void TopLevel::faxOpen() { KURL url = KFileDialog::getOpenURL(TQString(), KFAX_FILETYPES); faxOpen( url ); actRecent->addURL( fileURL ); } void TopLevel::faxOpen( const KURL & url ) { if (!url.isValid()) return; faxClose(); faxAdd( url ); fileURL = url; updateActions(); } void TopLevel::faxAdd() { KURL url = KFileDialog::getOpenURL(TQString(), KFAX_FILETYPES); faxAdd( url ); actRecent->addURL( fileURL ); } void TopLevel::faxAdd( const KURL & url ) { if (!url.isValid()) return; openNetFile(url); updateGoActions(); } void TopLevel::faxSave() { saveNetFile(fileURL); } void TopLevel::faxSaveAs() { fileURL = KFileDialog::getSaveURL(TQString(), KFAX_FILETYPES); if (fileURL.isEmpty()) return; faxSave(); actRecent->addURL( fileURL ); } static void freeImages() { int i; for (i = 1; i < MAXZOOM; i++) { if (Images[i]) FreeImage(Images[i]); Images[i] = NULL; } } static XImage *generateZoomImages(int maxzoom) { int i; for (i = 1; i < MAXZOOM; i++){ if (!Images[i-1]) continue; Image = Images[i] = ZoomImage(Images[i-1]); if(Image == NULL){// out of memory Image = Images[i -1]; break; } } i = maxzoom; while (!Images[i]) i--; return Images[i]; } void TopLevel::zoom( int factor ) { if(!thispage || !Image || !faxqtwin || !display_is_setup) return; Resize = Refresh = 1; Image = generateZoomImages(factor); PaneWidth = Image->width; PaneHeight = Image->height; resizeView(); putImage(); uiUpdate(); updateZoomActions(); } void TopLevel::zoomin() { if ( oz > 0 ) { oz--; zoom( oz ); } } void TopLevel::zoomout() { if (oz < MAXZOOM && Image->width >= 256) { ++oz; zoom( oz ); } } void TopLevel::actualSize() { oz = 0; zoom( oz ); } void loadfile(TQString filename) { // Typical FAX resolutions are: // Standard: 203 dpi x 98 dpi // Fine: 203 dpi x 196 lpi // Super Fine: 203 dpi y 392 lpi, or // 406 dpi x 392 lpi TQSize dpi(203,196); KFileMetaInfo metaInfo(filename); if (metaInfo.isValid() && metaInfo.item("Resolution").isValid()) { TQSize s = metaInfo.item("Resolution").value().toSize(); if (s.width() >= 100 && s.height() >= 100) dpi = s; } (void) notetiff(TQFile::encodeName(filename)); struct pagenode *pn; for(pn = firstpage; pn; pn = pn->next) if (!pn->dpiX) { pn->dpiX = dpi.width(); pn->dpiY = dpi.height(); } } void TopLevel::openadd(TQString filename) { auxpage = lastpage; loadfile(filename); if( firstpage != lastpage ) { if(auxpage->next) auxpage = auxpage->next; } // auxpage should now point to the first pagenode which was created for // the newly added fax file. have_no_fax = false; thispage = auxpage; newPage(); resizeView(); putImage(); } void TopLevel::resizeEvent(TQResizeEvent *e) { KMainWindow::resizeEvent(e); resizeView(); } void TopLevel::wheelEvent( TQWheelEvent *e ) { e->accept(); if ( e->state() & ShiftButton ) { if ( e->delta() < 0 ) zoomin(); else zoomout(); } else { int offset = TQApplication::wheelScrollLines()*vsb->lineStep(); if ( e->state() & ControlButton ) offset = vsb->pageStep(); offset = -e->delta()*offset/120; vsb->setValue( vsb->value() + offset ); } } void TopLevel::resizeView() { if(!faxqtwin || !display_is_setup) return; //printf("In resizeView() entered\n"); qwindow_width = faxqtwin->width(); qwindow_height = faxqtwin->height(); if( hsb->isVisible()) qwindow_height -= 16; if( vsb->isVisible()) qwindow_width -= 16; if(Image){ PaneWidth = Image->width; PaneHeight = Image->height; } // printf("faxw %d qtw %d\n", PaneWidth , faxqtwin->width()); if( (PaneHeight > qwindow_height ) && (PaneWidth > qwindow_width)){ vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()-16); hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width()-16,16); qwindow_width = faxqtwin->width() -16; qwindow_height = faxqtwin->height()-16; vsb->raise(); vsb->show(); hsb->show(); } else{ if( PaneHeight > qwindow_height){ vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()); qwindow_width = faxqtwin->width() -16 ; qwindow_height = faxqtwin->height(); vsb->show(); hsb->hide(); hsb->raise(); } else vsb->hide(); if( PaneWidth > qwindow_width ){ hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width(),16); hsb->show(); hsb->raise(); vsb->hide(); qwindow_width = faxqtwin->width() ; qwindow_height = faxqtwin->height() -16; } else hsb->hide(); } if(Image){ hsb->setRange(0,TQMAX(0,Image->width - qwindow_width)); hsb->setSteps(5,qwindow_width/2); // printf("hsb range: %d\n",TQMAX(0,Image->width - qwindow_width)); vsb->setRange(0,TQMAX(0,Image->height - qwindow_height)); vsb->setSteps(5,qwindow_height/2); // printf("vsb range: %d\n",TQMAX(0,Image->height - qwindow_height)); // printf("vsb TQMIN %d vdb TQMAX %d\n",vsb->TQMINValue(),vsb->TQMAXValue()); } Resize = 1; uiUpdate(); } bool TopLevel::loadAllPages( int &numpages, int ¤tpage ) { struct pagenode *pn; numpages = 0; currentpage = 1; for(pn = firstpage; pn; pn = pn->next) { ++numpages; if (pn == thispage) currentpage = numpages; if (!Pimage(pn)) { int k = -1; while((k != 0) && (k != 3) && (k != 1)) k = GetImage(pn); // fetch image if it is not available yet. } } return (numpages != 0); } void TopLevel::print(){ if(!thispage || !firstpage) { return KMessageBox::sorry(this, i18n("There is no document active.")); } int pages, currentpage; loadAllPages(pages, currentpage); KPrinter printer(true, TQPrinter::HighResolution); printer.setFullPage( true ); printer.setUsePrinterResolution( true ); printer.setCreator( i18n("KFax") + " " KFAXVERSION ); printer.setDocName( TQString("%1 - %2").arg(firstpage->name).arg(i18n("KFax"))); printer.setDocFileName( firstpage->name ); printer.setPageSelection( KPrinter::ApplicationSide ); printer.setMinMax( 1, pages ); printer.setCurrentPage( currentpage ); printer.addDialogPage(new KFAXPrintSettings()); if ( !printer.setup( this ) ) return; TQPainter painter; painter.begin( &printer ); printIt(printer, painter); painter.end(); } void TopLevel::printIt( KPrinter &printer, TQPainter &painter ) { TQPaintDeviceMetrics dm(painter.device()); TQApplication::setOverrideCursor( waitCursor ); kapp->processEvents(); const bool fullpage = printer.option(APP_KFAX_SCALE_FULLPAGE) == "true"; const bool center_h = printer.option(APP_KFAX_CENTER_HORZ) == "true"; const bool center_v = printer.option(APP_KFAX_CENTER_VERT) == "true"; int currentpage = 0; bool first_page_printed = false; struct pagenode *pn; for(pn = firstpage; pn; pn = pn->next) { ++currentpage; // should this page be printed ? if (printer.pageList().findIndex(currentpage) < 0) continue; XImage *Image = Pimage(pn); if (!Image) continue; // byte-swapping the image TQByteArray bytes( Image->height*Image->bytes_per_line ); for (int y=Image->height-1; y>=0; --y) { TQ_UINT32 offset = y*Image->bytes_per_line; TQ_UINT32 *source = (TQ_UINT32 *) (Image->data + offset); TQ_UINT32 *dest = (TQ_UINT32 *) (bytes.data() + offset); for (int x=(Image->bytes_per_line/4)-1; x>=0; --x) { TQ_UINT32 dv = 0, sv = *source; for (int bit=32; bit>0; --bit) { dv <<= 1; dv |= sv&1; sv >>= 1; } *dest = dv; ++dest; ++source; } } TQImage image( (uchar *)bytes.data(), Image->bytes_per_line*8, Image->height, 1, NULL, 2, TQImage::LittleEndian); if (first_page_printed) printer.newPage(); first_page_printed = true; const TQSize printersize( dm.width(), dm.height() ); kdDebug() << "Printersize = " << printersize << endl; // print Image in original size if possible, else scale it. const TQSize size( // logical size of the image Image->width * dm.logicalDpiX() / pn->dpiX, Image->height * dm.logicalDpiY() / pn->dpiY ); kdDebug() << "Org image size = " << Image->width << "x" << Image->height << " logical picture res = " << pn->dpiX << "x" << pn->dpiY << endl; kdDebug() << "New image size = " << size << " logical printer res = " << dm.logicalDpiX() << "x" << dm.logicalDpiY() << endl; uint top, left, bottom, right; if (fullpage) top = left = bottom = right = 0; else printer.margins( &top, &left, &bottom, &right ); kdDebug() << "Margins = " << top << " " << left << " " << bottom << " " << right << endl; const TQSize maxSize( printersize.width()-left-right, printersize.height()-top-bottom ); TQSize scaledImageSize = size; if (size.width() > maxSize.width() || size.height() > maxSize.height() ) { // Image does not fit - scale it and print centered scaledImageSize.scale( maxSize, TQSize::ScaleMin ); kdDebug() << "Image does not fit - scaling to " << maxSize << endl; } else { // Image does fit - print it in original size, but centered scaledImageSize.scale( size, TQSize::ScaleMin ); kdDebug() << "Image does fit - scaling to " << size << endl; } kdDebug() << "Final image size " << scaledImageSize << endl; int x,y; if (center_h) x = (maxSize.width()-scaledImageSize.width())/2 + left; else x = left; if (center_v) y = (maxSize.height()-scaledImageSize.height())/2 + top; else y = top; painter.drawImage( TQRect(x,y,scaledImageSize.width(), scaledImageSize.height()), image ); } TQApplication::restoreOverrideCursor(); } void TopLevel::saveNetFile( const KURL& dest) { if ( !dest.isValid() ) { KMessageBox::sorry(this, i18n("Malformed URL")); return; } statusbar->message( i18n( "Saving..." ) ); KURL source = KURL::fromPathOrURL(thispage->pathname); bool ok = KIO::NetAccess::file_copy( source, dest, -1, true, false, this); statusbar->clear(); if (!ok) KMessageBox::error(this, i18n("Failure in 'copy file()'\n" "Could not save file!")); } void TopLevel::openNetFile( const KURL &u) { if ( !u.isValid() ) { KMessageBox::error(this, i18n("Malformed URL")); return; } if ( u.isLocalFile() ) { TQString string = i18n("Loading '%1'").arg(u.path()); statusbar->message(string); openadd( u.path()); statusbar->clear(); } else { statusbar->message(i18n("Downloading...")); TQString tmpFile = TQString(); if ( KIO::NetAccess::download( u, tmpFile, this ) ) { openadd( tmpFile ); setCaption( u.prettyURL() ); } statusbar->clear(); KIO::NetAccess::removeTempFile( tmpFile ); } } void TopLevel::dragEnterEvent( TQDragEnterEvent * event) { event->accept(KURLDrag::canDecode(event)); } void TopLevel::dropEvent( TQDropEvent * event) { KURL::List list; if (KURLDrag::decode(event, list) && !list.isEmpty()) { // Load the first file in this window const KURL &url = list.first(); openNetFile( url ); } } void SetupDisplay(){ if(display_is_setup){ return; } display_is_setup = TRUE; xpos = ypos = ox = oy = 0; ExpectConfNotify = 1; /* XSizeHints size_hints;*/ Win = XCreateSimpleWindow(qtdisplay,qtwin,1,1, 1,1, 0, BlackPixel(qtdisplay,XDefaultScreen(qtdisplay)), WhitePixel(qtdisplay,XDefaultScreen(qtdisplay))); PaintGC = XCreateGC(qtdisplay, Win, 0L, (XGCValues *) NULL); XSetForeground(qtdisplay, PaintGC, BlackPixel(qtdisplay, XDefaultScreen(qtdisplay) )); XSetBackground(qtdisplay, PaintGC, WhitePixel(qtdisplay, XDefaultScreen(qtdisplay) )); XSetFunction(qtdisplay, PaintGC, GXcopy); WorkCursor = XCreateFontCursor(qtdisplay, XC_watch); //ReadyCursor = XCreateFontCursor(qtdisplay, XC_plus); ReadyCursor = XCreateFontCursor(qtdisplay, XC_hand2); MoveCursor = XCreateFontCursor(qtdisplay, XC_fleur); LRCursor = XCreateFontCursor(qtdisplay, XC_sb_h_double_arrow); UDCursor = XCreateFontCursor(qtdisplay, XC_sb_v_double_arrow); XSelectInput(qtdisplay, Win, Button2MotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | KeyPressMask | SubstructureNotifyMask | LeaveWindowMask | OwnerGrabButtonMask | StructureNotifyMask); XMapRaised(qtdisplay, Win); XDefineCursor(qtdisplay, Win, ReadyCursor); XFlush(qtdisplay); memset(Images, 0, sizeof(Images)); // Start at half the Size oz = 1; } void TopLevel::handle_X_event(XEvent Event) { if(!thispage || !Image || !faxqtwin || !display_is_setup) return; bool putimage = false; // Do we actually have to write the image to the scree? do { switch(Event.type) { case MappingNotify: XRefreshKeyboardMapping((XMappingEvent *)(&Event)); break; case LeaveNotify: /* buttondown = false; XDefineCursor(qtdisplay, Win, ReadyCursor); XFlush(qtdisplay);*/ break; case Expose: { if(Event.xexpose.count != 0) break; if(!Image) break; putimage = TRUE; } break; case KeyPress: if (ExpectConfNotify && (Event.xkey.time < (Lasttime + PATIENCE))) break; Lasttime = Event.xkey.time; ExpectConfNotify = 0; switch(XkbKeycodeToKeysym(qtdisplay, Event.xkey.keycode, 0, 0)) { case XK_m: mirrorPage(); if (Event.xkey.state & ShiftMask) TurnFollowing(TURN_M, thispage->next); break; case XK_o: zoomout(); break; case XK_i: zoomin(); break; case XK_Up: ypos-= qwindow_height / 3; putimage = TRUE; break; case XK_Down: ypos+= qwindow_height / 3; putimage = TRUE; break; case XK_Left: xpos-= qwindow_width / 4; putimage = TRUE; break; case XK_Right: xpos+= qwindow_width / 4; putimage = TRUE; break; case XK_Home: case XK_R7: if (Event.xkey.state & ShiftMask) { thispage = firstpage; newPage(); resizeView(); putImage(); break; } xpos= 0; ypos= 0; putImage(); break; case XK_End: case XK_R13: if (Event.xkey.state & ShiftMask) { thispage = lastpage; newPage(); resizeView(); putImage(); break; } xpos= Image->width; ypos= Image->height; putImage(); break; case XK_l: case XK_r: rotatePage(); if (Event.xkey.state & ShiftMask) TurnFollowing(TURN_L, thispage->next); break; case XK_p: case XK_minus: case XK_Prior: case XK_R9: case XK_BackSpace: prevPage(); break; case XK_n: case XK_plus: case XK_space: case XK_Next: case XK_R15: nextPage(); break; case XK_u: flipPage(); if (Event.xkey.state & ShiftMask) TurnFollowing(TURN_U, thispage->next); break; case XK_q: if (viewpage) { thispage = viewpage; viewpage = NULL; newPage(); resizeView(); putImage(); } } break; case ButtonPress: if (ExpectConfNotify && (Event.xbutton.time < (Lasttime + PATIENCE))) break; Lasttime = Event.xbutton.time; ExpectConfNotify = 0; switch (Event.xbutton.button) { case Button1: buttondown = true; switch (((Image->width > qwindow_width)<<1) | (Image->height > qwindow_height)) { case 0: break; case 1: XDefineCursor(qtdisplay, Win, UDCursor); break; case 2: XDefineCursor(qtdisplay, Win, LRCursor); break; case 3: XDefineCursor(qtdisplay, Win, MoveCursor); } XFlush(qtdisplay); offx = Event.xbutton.x; offy = Event.xbutton.y; break; } break; case MotionNotify: if(!buttondown) break; do { nx = Event.xmotion.x; ny = Event.xmotion.y; } while (XCheckTypedEvent(qtdisplay, MotionNotify, &Event)); xpos+= offx - nx; ypos+= offy - ny; offx = nx; offy = ny; putimage = TRUE; break; case ButtonRelease: if (Event.xbutton.button == Button1) { buttondown = false; XDefineCursor(qtdisplay, Win, ReadyCursor); XFlush(qtdisplay); } } } while (XCheckWindowEvent(qtdisplay, Win, KeyPressMask|ButtonPressMask, &Event)); if(putimage == TRUE) { Refresh = Resize = 1; putImage(); } } void TopLevel::rotatePage() { if(!thispage || !Image || !faxqtwin || !display_is_setup) return; XDefineCursor(qtdisplay, Win, WorkCursor); XFlush(qtdisplay); XImage *newrotimage = RotImage(Images[0]); XDefineCursor(qtdisplay, Win, ReadyCursor); if(newrotimage == NULL){ // out of memory return; } thispage->extra = Images[0] = newrotimage; thispage->orient ^= TURN_L; freeImages(); Image = generateZoomImages(oz); { int t = xpos ; xpos= ypos; ypos= t; } Refresh = Resize = 1; putImage(); } void TopLevel::flipPage() { if(!thispage || !Image || !faxqtwin || !display_is_setup) return; XDefineCursor(qtdisplay, Win, WorkCursor); XFlush(qtdisplay); XImage *newflipimage = FlipImage(Images[0]); XDefineCursor(qtdisplay, Win, ReadyCursor); if(newflipimage == NULL){ // out of memory return; } thispage->extra = Images[0] = newflipimage; thispage->orient ^= TURN_U; freeImages(); Image = generateZoomImages(oz); Refresh = Resize = 1; putImage(); } void TopLevel::mirrorPage() { if(!thispage || !Image || !faxqtwin || !display_is_setup) return; XDefineCursor(qtdisplay, Win, WorkCursor); XFlush(qtdisplay); XImage *newmirror = MirrorImage(Images[0]); XDefineCursor(qtdisplay, Win, ReadyCursor); if(newmirror == NULL){ // out of memory return; } thispage->extra = Images[0] = newmirror; thispage->orient ^= TURN_M; freeImages(); Image = generateZoomImages(oz); Refresh = Resize = 1; putImage(); } void TopLevel::scrollHorz(int){ if(!Image) return; // printf("hsb value: %d\n",hsb->value()); xpos= hsb->value() + qwindow_width/2; Refresh = 1; putImage(); } void TopLevel::scrollVert(int ){ if(!Image) return; // printf("vsb value: %d\n",vsb->value()); ypos= vsb->value() + qwindow_height/2; Refresh = 1; putImage(); } void TopLevel::lastPage() { if(!thispage) return; if ( thispage->next ) { while(thispage->next != NULL) thispage = thispage->next; newPage(); resizeView(); putImage(); } updateGoActions(); } void TopLevel::firstPage() { if(!thispage) return; if ( thispage->prev ) { while(thispage->prev != NULL) thispage = thispage->prev; newPage(); resizeView(); putImage(); } updateGoActions(); } void TopLevel::nextPage() { if(!thispage) return; if (thispage->next) { thispage = thispage->next; newPage(); resizeView(); putImage(); } updateGoActions(); } void TopLevel::prevPage() { if(!thispage) return; if (thispage->prev) { thispage = thispage->prev; newPage(); resizeView(); putImage(); } updateGoActions(); } void TopLevel::newPage(){ if(!display_is_setup) SetupDisplay(); XDefineCursor(qtdisplay, Win, WorkCursor); XFlush(qtdisplay); freeImages(); int k = -1; if(!thispage) { XDefineCursor(qtdisplay, Win, ReadyCursor); return; } if (Pimage(thispage) == NULL){ while((k != 0) && (k != 3) && (k !=1)) k = GetImage(thispage); } if (k == 3 ){ XDefineCursor(qtdisplay, Win, ReadyCursor); FreeFax(); /* KMessageBox::sorry(i18n("Bad fax file k=3"));*/ return; } if (k == 0 ){ XDefineCursor(qtdisplay, Win, ReadyCursor); FreeFax(); /* KMessageBox::sorry(i18n("Bad fax file k=0"));*/ return; } Image = Images[0] = Pimage(thispage); setCaption(TQFile::decodeName(thispage->name)); Image = generateZoomImages(oz); PaneWidth = Image->width; PaneHeight = Image->height; Refresh = 1; XDefineCursor(qtdisplay, Win, ReadyCursor); uiUpdate(); } void TopLevel::faxClose() { FreeFax(); setCaption(i18n("KFax")); // TODO replace this with unmapping the window. if(display_is_setup) XResizeWindow(qtdisplay,Win,1,1); // we want a clear gray background. resizeView(); vsb->hide(); hsb->hide(); fileURL = TQString(); updateActions(); } void TopLevel::FreeFax() { if(display_is_setup) XClearWindow(qtdisplay, Win); freeImages(); pagenode *pn; for (pn = firstpage; pn; pn = pn->next){ if(Pimage(pn)){ FreeImage(Pimage(pn)); pn->extra = NULL; } } Image = NULL; for (pn = firstpage; pn; pn = pn->next){ if(pn->pathname){ free(pn->pathname); } } if(firstpage){ for(pn = firstpage->next; pn; pn = pn->next){ if(pn->prev){ free(pn->prev); } } } if(lastpage) free(lastpage); firstpage = lastpage = viewpage = thispage = auxpage = NULL; uiUpdate(); } void TopLevel::uiUpdate(){ if(thispage){ struct pagenode *pn ; int pages = 0; int currentpage = 0; for(pn = firstpage; pn ; pn = pn->next){ pages ++; if (thispage == pn) currentpage = pages; } TQString pagestr = i18n("Page: %1 of %2").arg(currentpage).arg(pages); statusbar->changeItem(pagestr, ID_PAGE_NO); if(Image){ TQString wh = i18n("W: %1 H: %2").arg(Image->width).arg(Image->height); statusbar->changeItem(wh, ID_INS_OVR); } TQString resolution = i18n("Res: %1").arg(thispage->vres?i18n("Fine"):i18n("Normal")); // TODO: resolution += TQString("%1x%2").arg(thispage->dpiX).arg(thispage->dpiY); statusbar->changeItem(resolution, ID_GENERAL); statusbar->changeItem(thispage->name, ID_FNAME); TQString typestring; if(thispage->type == FAX_TIFF){ typestring = i18n("Type: Tiff "); } else if ( thispage->type == FAX_RAW){ typestring = i18n("Type: Raw "); } if ( thispage->expander == g31expand ) typestring += "G3"; if ( thispage->expander == g32expand ) typestring += "G3 2D"; if ( thispage->expander == g4expand ) typestring += "G4"; statusbar->changeItem(typestring,ID_TYPE); updateActions(); } } void kfaxerror(const TQString& title, const TQString& error){ KMessageBox::error(toplevel, error, title); } void TopLevel::putImage() { // TODO do I really need to set Refresh or Resize to 1 , is there // really still someonce calling this with out haveing set Refresh or Resize to 1? if ( !Image || !display_is_setup || !thispage ) return; if ( qwindow_width > Image->width){ xpos= Image->width/2; } else{ if(xpos< qwindow_width/2){ xpos = qwindow_width/2; } else{ if(xpos> Image->width - qwindow_width/2){ xpos= Image->width - qwindow_width/2; } } } if ( qwindow_height > Image->height){ ypos= Image->height/2; } else{ if(ypos< qwindow_height/2){ ypos = qwindow_height/2; } else{ if(ypos> Image->height - qwindow_height/2){ ypos= Image->height - qwindow_height/2; } } } if (xpos!= ox || ypos!= oy || Refresh || Resize){ /* In the following we use qwindow_height -1 etc since the main view has a sunken frame and I need to offset by 1 pixel to the right and one pixel down so that I don't paint my fax into the border of the frame*/ XResizeWindow(qtdisplay,Win,TQMIN(qwindow_width -1,Image->width ), TQMIN(qwindow_height -1,Image->height )); XPutImage(qtdisplay, Win, PaintGC, Image, TQMAX(xpos - qwindow_width/2,0), TQMAX(ypos - qwindow_height/2,0), 0, 0, TQMIN(qwindow_width -1,Image->width) , TQMIN(qwindow_height -1,Image->height) ); vsb->setValue(TQMAX(ypos - qwindow_height/2,0)); hsb->setValue(TQMAX(xpos - qwindow_width/2,0)); XFlush(qtdisplay); } ox = xpos; oy = ypos; Resize = Refresh = 0; } void TopLevel::faxoptions(){ OptionsDialog * opd = new OptionsDialog(this, "options"); opd->setWidgets(&fop); if(opd->exec()){ struct optionsinfo *newops; newops = opd->getInfo(); fop.resauto = newops->resauto; fop.geomauto = newops->geomauto; fop.width = newops->width; fop.height = newops->height; fop.fine = newops->fine; fop.landscape= newops->landscape; fop.flip = newops->flip; fop.invert = newops->invert; fop.lsbfirst = newops->lsbfirst; fop.raw = newops->raw; setFaxDefaults(); writeSettings(); } delete opd; } void setFaxDefaults(){ // fop is called in readSettings, so this can't be // called after a TopLevel::readSettings() if(have_cmd_opt ) // we have commad line options all kfaxrc defaults are return; // overridden if(fop.resauto == 1) defaultpage.vres = -1; else defaultpage.vres = fop.fine; if(fop.geomauto == 1){ defaultpage.width = defaultpage.height = 0; } else{ defaultpage.width = fop.width; defaultpage.height = fop.height; } if(fop.landscape) defaultpage.orient |= TURN_L; if(fop.flip) defaultpage.orient |= TURN_U; defaultpage.inverse = fop.invert; defaultpage.lsbfirst = fop.lsbfirst; switch (fop.raw) { case 2: defaultpage.expander = g32expand; break; case 4: defaultpage.expander = g4expand; break; default:defaultpage.expander = g31expand; } } static const char description[] = I18N_NOOP("TDE G3/G4 Fax Viewer"); static KCmdLineOptions options[] = { {"f", 0, 0 }, {"fine", I18N_NOOP( "Fine resolution" ), 0 }, {"n", 0, 0 }, {"normal", I18N_NOOP( "Normal resolution" ), 0 }, {"height", I18N_NOOP( "Height (number of fax lines)" ), 0 }, {"w", 0, 0 }, {"width", I18N_NOOP( "Width (dots per fax line)" ), 0 }, {"l", 0, 0 }, {"landscape", I18N_NOOP( "Turn image 90 degrees (landscape mode)" ), 0 }, {"u", 0, 0 }, {"upsidedown", I18N_NOOP( "Turn image upside down" ), 0 }, {"i", 0, 0 }, {"invert", I18N_NOOP( "Invert black and white" ), 0 }, {"m", 0, 0 }, {"mem ", I18N_NOOP( "Limit memory use to 'bytes'" ), "8M" }, {"r", 0, 0 }, {"reverse", I18N_NOOP( "Fax data is packed lsb first" ), 0 }, {"2" , I18N_NOOP( "Raw files are g3-2d" ), 0 }, {"4", I18N_NOOP( "Raw files are g4" ), 0 }, {"+file(s)", I18N_NOOP( "Fax file(s) to show" ), 0 }, KCmdLineLastOption }; int main (int argc, char **argv) { KAboutData aboutData( "kfax", I18N_NOOP("KFax"), KFAXVERSION, description, KAboutData::License_GPL, "(c) 1997-98 Bernd Johannes Wuebben"); aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@kde.org" ); aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "UI Rewrite, lots of code " "cleanups and fixes" ), "nhasan@kde.org" ); aboutData.addCredit( "Helge Deller", I18N_NOOP( "Printing Rewrite, lots of code " "cleanups and fixes"), "deller@kde.org" ); TDECmdLineArgs::init(argc, argv, &aboutData); TDECmdLineArgs::addCmdLineOptions( options ); MyApp a; qtdisplay = tqt_xdisplay(); viewfaxmain(); toplevel = new TopLevel(); toplevel->show(); startingup = 1; a.processEvents(); a.flushX(); startingup = 0; faxinit(); if(!have_no_fax){ thispage = firstpage; toplevel->newPage(); toplevel->resizeView(); //TODO : I don't think I need this putImage(); toplevel->putImage(); } toplevel->uiUpdate(); return a.exec (); } #include "kfax.moc"