/*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2002 by Chris Cheney * * Copyright (C) 2002 by Malcolm Hunter * * Copyright (C) 2003-2004 by Christophe Devriese * * * * Copyright (C) 2003 by Daniel Molkentin * * Copyright (C) 2003 by Andy Goossens * * Copyright (C) 2003 by Dirk Mueller * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2004 by Dominique Devriese * * Copyright (C) 2004 by Christoph Cullmann * * Copyright (C) 2004 by Henrique Pinto * * Copyright (C) 2004 by Waldo Bastian * * Copyright (C) 2004 by Albert Astals Cid * * Copyright (C) 2004 by Antti Markus * * * * 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. * ***************************************************************************/ // qt/kde includes #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 // local includes #include "part.h" #include "ui/pageview.h" #include "ui/toc.h" #include "ui/searchwidget.h" #include "ui/thumbnaillist.h" #include "ui/side_reviews.h" #include "ui/minibar.h" #include "ui/newstuff.h" #include "ui/propertiesdialog.h" #include "ui/presentationwidget.h" #include "conf/preferencesdialog.h" #include "conf/settings.h" #include "core/document.h" #include "core/generator.h" #include "core/page.h" // definition of searchID for this class #define PART_SEARCH_ID 1 typedef KParts::GenericFactory KPDFPartFactory; K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory) using namespace KPDF; Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_viewportDirty( 0 ), m_showMenuBarAction(0), m_showFullScreenAction(0), m_actionsSearched(false), m_searchStarted(false) { // load catalog for translation KGlobal::locale()->insertCatalogue("kpdf"); // create browser extension (for printing when embedded into browser) m_bExtension = new BrowserExtension(this); // we need an instance setInstance(KPDFPartFactory::instance()); // build the document m_document = new KPDFDocument(&m_loadedGenerators); connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); connect( m_document, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) ); connect( m_document, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) ); connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); // widgets: ^searchbar (toolbar containing label and SearchWidget) // m_searchToolBar = new KToolBar( parentWidget, "searchBar" ); // m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() ); // QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" ); // m_searchWidget = new SearchWidget( m_searchToolBar, m_document ); // sLabel->setBuddy( m_searchWidget ); // m_searchToolBar->setStretchableWidget( m_searchWidget ); // widgets: [] splitter [] m_splitter = new QSplitter( parentWidget, widgetName ); m_splitter->setOpaqueResize( true ); m_splitter->setChildrenCollapsible( false ); setWidget( m_splitter ); // widgets: [left panel] | [] m_leftPanel = new QWidget( m_splitter ); m_leftPanel->setMinimumWidth( 90 ); m_leftPanel->setMaximumWidth( 300 ); QVBoxLayout * leftPanelLayout = new QVBoxLayout( m_leftPanel ); // widgets: [left toolbox/..] | [] m_toolBox = new QToolBox( m_leftPanel ); leftPanelLayout->addWidget( m_toolBox ); int tbIndex; // [left toolbox: Table of Contents] | [] //QFrame * tocFrame = new QFrame( m_toolBox ); //QVBoxLayout * tocFrameLayout = new QVBoxLayout( tocFrame ); TOC * toc = new TOC( m_toolBox/*tocFrame*/, m_document ); connect( toc, SIGNAL( hasTOC( bool ) ), this, SLOT( enableTOC( bool ) ) ); //KListViewSearchLine * tocSearchLine = new KListViewSearchLine( tocFrame, toc ); //tocFrameLayout->addWidget( tocSearchLine ); //tocFrameLayout->addWidget( toc ); tbIndex = m_toolBox->addItem( toc/*tocFrame*/, QIconSet(SmallIcon("text_left")), i18n("Contents") ); m_toolBox->setItemToolTip( tbIndex, i18n("Contents") ); enableTOC( false ); // [left toolbox: Thumbnails and Bookmarks] | [] QVBox * thumbsBox = new ThumbnailsBox( m_toolBox ); thumbsBox->setSpacing( 4 ); m_searchWidget = new SearchWidget( thumbsBox, m_document ); m_thumbnailList = new ThumbnailList( thumbsBox, m_document ); // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList ); connect( m_thumbnailList, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & )) ); connect( m_thumbnailList, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); // shrink the bottom controller toolbar (too hackish..) thumbsBox->setStretchFactor( m_searchWidget, 100 ); thumbsBox->setStretchFactor( m_thumbnailList, 100 ); // thumbsBox->setStretchFactor( m_tc, 1 ); tbIndex = m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); m_toolBox->setItemToolTip( tbIndex, i18n("Thumbnails") ); m_toolBox->setCurrentItem( thumbsBox ); // [left toolbox: Reviews] | [] Reviews * reviewsWidget = new Reviews( m_toolBox, m_document ); m_toolBox->addItem( reviewsWidget, QIconSet(SmallIcon("pencil")), i18n("Reviews") ); // widgets: [../miniBarContainer] | [] QWidget * miniBarContainer = new QWidget( m_leftPanel ); leftPanelLayout->addWidget( miniBarContainer ); QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer ); // widgets: [../[spacer/..]] | [] QWidget * miniSpacer = new QWidget( miniBarContainer ); miniSpacer->setFixedHeight( 6 ); miniBarLayout->addWidget( miniSpacer ); // widgets: [../[../MiniBar]] | [] MiniBar * miniBar = new MiniBar( miniBarContainer, m_document ); miniBarLayout->addWidget( miniBar ); // widgets: [] | [right 'pageView'] // QWidget * rightContainer = new QWidget( m_splitter ); // QVBoxLayout * rightLayout = new QVBoxLayout( rightContainer ); // KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" ); // rightLayout->addWidget( rtb ); m_pageView = new PageView( m_splitter, m_document ); m_pageView->setFocus(); //usability setting connect( m_pageView, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & ))); connect( m_pageView, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); connect( m_document, SIGNAL(error(QString&,int )),m_pageView,SLOT(errorMessage(QString&,int ))); connect( m_document, SIGNAL(warning(QString&,int )),m_pageView,SLOT(warningMessage(QString&,int ))); connect( m_document, SIGNAL(notice(QString&,int )),m_pageView,SLOT(noticeMessage(QString&,int ))); // rightLayout->addWidget( m_pageView ); // add document observers m_document->addObserver( this ); m_document->addObserver( m_thumbnailList ); m_document->addObserver( m_pageView ); m_document->addObserver( toc ); m_document->addObserver( miniBar ); m_document->addObserver( reviewsWidget ); // ACTIONS KActionCollection * ac = actionCollection(); // Page Traversal actions m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ), ac, "goto_page" ); m_gotoPage->setShortcut( "CTRL+G" ); // dirty way to activate gotopage when pressing miniBar's button connect( miniBar, SIGNAL( gotoPage() ), m_gotoPage, SLOT( activate() ) ); m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()), ac, "previous_page"); m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); m_prevPage->setShortcut( "Backspace" ); // dirty way to activate prev page when pressing miniBar's button connect( miniBar, SIGNAL( prevPage() ), m_prevPage, SLOT( activate() ) ); m_nextPage = KStdAction::next(this, SLOT(slotNextPage()), ac, "next_page" ); m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); m_nextPage->setShortcut( "Space" ); // dirty way to activate next page when pressing miniBar's button connect( miniBar, SIGNAL( nextPage() ), m_nextPage, SLOT( activate() ) ); m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoFirst() ), ac, "first_page" ); m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); m_lastPage = KStdAction::lastPage( this, SLOT( slotGotoLast() ), ac, "last_page" ); m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); m_historyBack = KStdAction::back( this, SLOT( slotHistoryBack() ), ac, "history_back" ); m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) ); m_historyNext = KStdAction::forward( this, SLOT( slotHistoryNext() ), ac, "history_forward" ); m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) ); // Find and other actions m_find = KStdAction::find( this, SLOT( slotFind() ), ac, "find" ); m_find->setEnabled( false ); m_findNext = KStdAction::findNext( this, SLOT( slotFindNext() ), ac, "find_next" ); m_findNext->setEnabled( false ); m_saveAs = KStdAction::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" ); m_saveAs->setEnabled( false ); KAction * prefs = KStdAction::preferences( this, SLOT( slotPreferences() ), ac, "preferences" ); prefs->setText( i18n( "Configure oKular..." ) ); // TODO: use "Configure PDF Viewer..." when used as part (like in konq QString constraint("([X-KDE-Priority] > 0) and (exist Library) and ([X-KDE-oKularHasInternalSettings])") ; KTrader::OfferList gens=KTrader::self()->query("oKular/Generator",constraint); if (gens.count() > 0) { KAction * genPrefs = KStdAction::preferences( this, SLOT( slotGeneratorPreferences() ), ac, "generator_prefs" ); genPrefs->setText( i18n( "Configure backends..." ) ); } m_printPreview = KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac ); m_printPreview->setEnabled( false ); m_showLeftPanel = new KToggleAction( i18n( "Show &Navigation panel"), "show_side_panel", 0, this, SLOT( slotShowLeftPanel() ), ac, "show_leftpanel" ); m_showLeftPanel->setShortcut( "CTRL+L" ); m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel" ) ); m_showLeftPanel->setChecked( Settings::showLeftPanel() ); slotShowLeftPanel(); QString app = KStandardDirs::findExe( "ps2pdf" ); if ( !app.isNull() ) KAction * importPS= new KAction(i18n("&Import Postscript as PDF..."), "psimport", 0, this, SLOT(slotImportPSFile()), ac, "import_ps"); KAction * ghns = new KAction(i18n("&Get Books From Internet..."), "knewstuff", 0, this, SLOT(slotGetNewStuff()), ac, "get_new_stuff"); ghns->setShortcut( "G" ); // TEMP, REMOVE ME! m_showProperties = new KAction(i18n("&Properties"), "info", 0, this, SLOT(slotShowProperties()), ac, "properties"); m_showProperties->setEnabled( false ); m_showPresentation = new KAction( i18n("P&resentation"), "kpresenter_kpr", "Ctrl+Shift+P", this, SLOT(slotShowPresentation()), ac, "presentation"); m_showPresentation->setEnabled( false ); // attach the actions of the children widgets too m_pageView->setupActions( ac ); // apply configuration (both internal settings and GUI configured items) QValueList splitterSizes = Settings::splitterSizes(); if ( !splitterSizes.count() ) { // the first time use 1/10 for the panel and 9/10 for the pageView splitterSizes.push_back( 50 ); splitterSizes.push_back( 500 ); } m_splitter->setSizes( splitterSizes ); // get notified about splitter size changes (HACK that will be removed // by connecting to Qt4::QSplitter's sliderMoved()) m_pageView->installEventFilter( this ); // document watcher and reloader m_watcher = new KDirWatch( this ); connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) ); m_dirtyHandler = new QTimer( this ); connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); slotNewConfig(); // [SPEECH] check for KTTSD presence and usability KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); Settings::setUseKTTSD( (offers.count() > 0) ); // set our XML-UI resource file setXMLFile("part.rc"); // updateViewActions(); } Part::~Part() { // save internal settings Settings::setSplitterSizes( m_splitter->sizes() ); // write to disk config file Settings::writeConfig(); delete m_document; } void Part::fillGenerators() { QString constraint("([X-KDE-Priority] > 0) and (exist Library) and ([X-KDE-oKularHasInternalSettings])") ; KTrader::OfferList offers=KTrader::self()->query("oKular/Generator",constraint); QString propName; int count=offers.count(); if (count > 0) { for (int i=0;iproperty("Name").toString(); // dont load already loaded generators if (! m_loadedGenerators.take( propName ) ) { KLibLoader *loader = KLibLoader::self(); if (!loader) { kdWarning() << "Could not start library loader: '" << loader->lastErrorMessage() << "'." << endl; return; } KLibrary *lib = loader->globalLibrary( QFile::encodeName( offers[i]->library() ) ); if (!lib) { kdWarning() << "Could not load '" << lib->fileName() << "' library." << endl; } Generator* (*create_plugin)(KPDFDocument* doc) = ( Generator* (*)(KPDFDocument* doc) ) lib->symbol( "create_plugin" ); // the generator should do anything with the document if we are only configuring m_loadedGenerators.insert(propName,create_plugin(m_document)); m_generatorsWithSettings << propName; } } m_loadedGenerators.setAutoDelete(true); } } void Part::slotGeneratorPreferences( ) { fillGenerators(); //Generator* gen= m_loadedGenerators[m_generatorsWithSettings[number]]; // an instance the dialog could be already created and could be cached, // in which case you want to display the cached dialog if ( KConfigDialog::showDialog( "generator_prefs" ) ) return; // we didn't find an instance of this dialog, so lets create it KConfigDialog * dialog = new KConfigDialog( m_pageView, "generator_prefs", Settings::self() ); QDictIterator it(m_loadedGenerators); for( ; it.current(); ++it ) { it.current()->addPages(dialog); } // (for now dont FIXME) keep us informed when the user changes settings // connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) ); dialog->show(); } void Part::notifyViewportChanged( bool /*smoothMove*/ ) { // update actions if the page is changed static int lastPage = -1; int viewportPage = m_document->viewport().pageNumber; if ( viewportPage != lastPage ) { updateViewActions(); lastPage = viewportPage; } } void Part::goToPage(uint i) { if ( i <= m_document->pages() ) m_document->setViewportPage( i - 1 ); } void Part::openDocument(KURL doc) { openURL(doc); } uint Part::pages() { return m_document->pages(); } uint Part::currentPage() { return m_document->pages() ? m_document->currentPage() + 1 : 0; } KURL Part::currentDocument() { return m_document->currentDocument(); } //this don't go anywhere but is required by genericfactory.h KAboutData* Part::createAboutData() { // the non-i18n name here must be the same as the directory in // which the part's rc file is installed ('partrcdir' in the // Makefile) KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1"); aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org"); return aboutData; } bool Part::slotImportPSFile() { KURL url = KFileDialog::getOpenURL( QString::null, "application/postscript" ); KTempFile tf( QString::null, ".pdf" ); if ( tf.status() == 0 && url.isLocalFile()) { tf.close(); m_file = url.path(); m_temporaryLocalFile = tf.name(); QString app = KStandardDirs::findExe( "ps2pdf" ); KProcess *p = new KProcess; *p << app; *p << m_file << m_temporaryLocalFile; m_pageView->displayMessage(i18n("Importing PS file as PDF (this may take a while)...")); connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded())); connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded())); p -> start(); return true; } m_temporaryLocalFile = QString::null; return false; } bool Part::openFile() { bool ok = m_document->openDocument( m_file, url() ); bool canSearch = m_document->supportsSearching(); // update one-time actions m_find->setEnabled( ok && canSearch ); m_findNext->setEnabled( ok && canSearch ); m_saveAs->setEnabled( ok ); m_printPreview->setEnabled( ok ); m_showProperties->setEnabled( ok ); m_showPresentation->setEnabled( ok ); // update viewing actions updateViewActions(); if ( !ok ) { // if can't open document, update windows so they display blank contents m_pageView->updateContents(); m_thumbnailList->updateContents(); return false; } // set the file to the fileWatcher if ( !m_watcher->contains(m_file) ) m_watcher->addFile(m_file); // if the 'StartFullScreen' flag is set, start presentation if ( m_document->getMetaData( "StartFullScreen" ) == "yes" ) { KMessageBox::information( m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString::null, "autoPresentationWarning" ); slotShowPresentation(); } /* if (m_document->getXMLFile() != QString::null) setXMLFile(m_document->getXMLFile(),true);*/ m_document->setupGUI(actionCollection(),m_toolBox); return true; } bool Part::openURL(const KURL &url) { // note: this can be the right place to check the file for gz or bz2 extension // if it matches then: download it (if not local) extract to a temp file using // KTar and proceed with the URL of the temporary file // this calls in sequence the 'closeURL' and 'openFile' methods bool openOk = KParts::ReadOnlyPart::openURL(url); m_bExtension->openURLNotify(); m_bExtension->setLocationBarURL( url.prettyURL() ); if ( openOk ) { m_viewportDirty = 0; } else KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); return openOk; } bool Part::closeURL() { if (!m_temporaryLocalFile.isNull()) { QFile::remove( m_temporaryLocalFile ); m_temporaryLocalFile = QString::null; } m_find->setEnabled( false ); m_findNext->setEnabled( false ); m_saveAs->setEnabled( false ); m_printPreview->setEnabled( false ); m_showProperties->setEnabled( false ); m_showPresentation->setEnabled( false ); updateViewActions(); m_searchStarted = false; if (!m_file.isEmpty()) m_watcher->removeFile(m_file); m_document->closeDocument(); m_searchWidget->clearText(); return KParts::ReadOnlyPart::closeURL(); } bool Part::eventFilter( QObject * watched, QEvent * e ) { // if pageView has been resized, save splitter sizes if ( watched == m_pageView && e->type() == QEvent::Resize ) Settings::setSplitterSizes( m_splitter->sizes() ); // only intercept events, don't block them return false; } void Part::slotShowLeftPanel() { bool showLeft = m_showLeftPanel->isChecked(); Settings::setShowLeftPanel( showLeft ); // show/hide left panel m_leftPanel->setShown( showLeft ); // this needs to be hidden explicitly to disable thumbnails gen m_thumbnailList->setShown( showLeft ); } void Part::slotFileDirty( const QString& fileName ) { // The beauty of this is that each start cancels the previous one. // This means that timeout() is only fired when there have // no changes to the file for the last 750 milisecs. // This ensures that we don't update on every other byte that gets // written to the file. if ( fileName == m_file ) { m_dirtyHandler->start( 750, true ); } } void Part::slotDoFileDirty() { // do the following the first time the file is reloaded if ( m_viewportDirty.pageNumber == -1 ) { // store the current viewport m_viewportDirty = DocumentViewport( m_document->viewport() ); // inform the user about the operation in progress m_pageView->displayMessage( i18n("Reloading the document...") ); } // close and (try to) reopen the document if ( KParts::ReadOnlyPart::openURL(m_file) ) { // on successfull opening, restore the previous viewport if ( m_viewportDirty.pageNumber >= (int) m_document->pages() ) m_viewportDirty.pageNumber = (int) m_document->pages() - 1; m_document->setViewport( m_viewportDirty ); m_viewportDirty.pageNumber = -1; } else { // start watching the file again (since we dropped it on close) m_watcher->addFile(m_file); m_dirtyHandler->start( 750, true ); } } void Part::updateViewActions() { bool opened = m_document->pages() > 0; if ( opened ) { bool atBegin = m_document->currentPage() < 1; bool atEnd = m_document->currentPage() >= (m_document->pages() - 1); m_gotoPage->setEnabled( m_document->pages() > 1 ); m_firstPage->setEnabled( !atBegin ); m_prevPage->setEnabled( !atBegin ); m_lastPage->setEnabled( !atEnd ); m_nextPage->setEnabled( !atEnd ); m_historyBack->setEnabled( !m_document->historyAtBegin() ); m_historyNext->setEnabled( !m_document->historyAtEnd() ); } else { m_gotoPage->setEnabled( false ); m_firstPage->setEnabled( false ); m_lastPage->setEnabled( false ); m_prevPage->setEnabled( false ); m_nextPage->setEnabled( false ); m_historyBack->setEnabled( false ); m_historyNext->setEnabled( false ); } } void Part::enableTOC(bool enable) { m_toolBox->setItemEnabled(0, enable); } //BEGIN go to page dialog class KPDFGotoPageDialog : public KDialogBase { public: KPDFGotoPageDialog(QWidget *p, int current, int max) : KDialogBase(p, 0L, true, i18n("Go to Page"), Ok | Cancel, Ok) { QWidget *w = new QWidget(this); setMainWidget(w); QVBoxLayout *topLayout = new QVBoxLayout( w, 0, spacingHint() ); e1 = new KIntNumInput(current, w); e1->setRange(1, max); e1->setEditFocus(true); QLabel *label = new QLabel( e1,i18n("&Page:"), w ); topLayout->addWidget(label); topLayout->addWidget(e1); topLayout->addSpacing(spacingHint()); // A little bit extra space topLayout->addStretch(10); e1->setFocus(); } int getPage() { return e1->value(); } protected: KIntNumInput *e1; }; //END go to page dialog void Part::slotGoToPage() { KPDFGotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() ); if ( pageDialog.exec() == QDialog::Accepted ) m_document->setViewportPage( pageDialog.getPage() - 1 ); } void Part::slotPreviousPage() { if ( !m_document->currentPage() < 1 ) m_document->setViewportPage( m_document->currentPage() - 1 ); } void Part::slotNextPage() { if ( m_document->currentPage() < (m_document->pages() - 1) ) m_document->setViewportPage( m_document->currentPage() + 1 ); } void Part::slotGotoFirst() { m_document->setViewportPage( 0 ); } void Part::slotGotoLast() { m_document->setViewportPage( m_document->pages() - 1 ); } void Part::slotHistoryBack() { m_document->setPrevViewport(); } void Part::slotHistoryNext() { m_document->setNextViewport(); } void Part::slotFind() { KFindDialog dlg( widget() ); dlg.setHasCursor( false ); #if KDE_IS_VERSION(3,3,90) dlg.setSupportsBackwardsFind( false ); dlg.setSupportsWholeWordsFind( false ); dlg.setSupportsRegularExpressionFind( false ); #endif if ( dlg.exec() == QDialog::Accepted ) { m_searchStarted = true; m_document->resetSearch( PART_SEARCH_ID ); m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, dlg.options() & KFindDialog::CaseSensitive, KPDFDocument::NextMatch, true, qRgb( 255, 255, 64 ) ); } } void Part::slotFindNext() { if ( m_searchStarted ) m_document->continueSearch( PART_SEARCH_ID ); else slotFind(); } void Part::slotSaveFileAs() { KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), QString::null, widget() ); if ( saveURL.isValid() && !saveURL.isEmpty() ) { if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) { if ( KMessageBox::questionYesNo( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename())) != KMessageBox::Yes ) return; } if ( !KIO::NetAccess::file_copy( url(), saveURL, -1, true ) ) KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) ); } } void Part::slotGetNewStuff() { // show the modal dialog over pageview and execute it NewStuffDialog * dialog = new NewStuffDialog( m_pageView ); dialog->exec(); delete dialog; } void Part::slotPreferences() { // an instance the dialog could be already created and could be cached, // in which case you want to display the cached dialog if ( PreferencesDialog::showDialog( "preferences" ) ) return; // we didn't find an instance of this dialog, so lets create it PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Settings::self() ); // keep us informed when the user changes settings connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) ); dialog->show(); } void Part::slotNewConfig() { // Apply settings here. A good policy is to check wether the setting has // changed before applying changes. // Watch File bool watchFile = Settings::watchFile(); if ( watchFile && m_watcher->isStopped() ) m_watcher->startScan(); if ( !watchFile && !m_watcher->isStopped() ) { m_dirtyHandler->stop(); m_watcher->stopScan(); } bool showSearch = Settings::showSearchBar(); if ( m_searchWidget->isShown() != showSearch ) m_searchWidget->setShown( showSearch ); // Main View (pageView) QScrollView::ScrollBarMode scrollBarMode = Settings::showScrollBars() ? QScrollView::AlwaysOn : QScrollView::AlwaysOff; if ( m_pageView->hScrollBarMode() != scrollBarMode ) { m_pageView->setHScrollBarMode( scrollBarMode ); m_pageView->setVScrollBarMode( scrollBarMode ); } // update document settings m_document->reparseConfig(); // update Main View and ThumbnailList contents // TODO do this only when changing Settings::renderMode() m_pageView->updateContents(); if ( Settings::showLeftPanel() && m_thumbnailList->isShown() ) m_thumbnailList->updateWidgets(); } void Part::slotPrintPreview() { if (m_document->pages() == 0) return; double width, height; int landscape, portrait; KPrinter printer; const KPDFPage *page; printer.setMinMax(1, m_document->pages()); printer.setPreviewOnly( true ); printer.setMargins(0, 0, 0, 0); // if some pages are landscape and others are not the most common win as kprinter does // not accept a per page setting landscape = 0; portrait = 0; for (uint i = 0; i < m_document->pages(); i++) { page = m_document->page(i); width = page->width(); height = page->height(); if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height); if (width > height) landscape++; else portrait++; } if (landscape > portrait) printer.setOption("orientation-requested", "4"); doPrint(printer); } void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) { bool reallyShow = false; if (!m_actionsSearched) { // the quest for options_show_menubar KXMLGUIClient *client; KActionCollection *ac; KActionPtrList::const_iterator it, end, begin; KActionPtrList actions; if (factory()) { QPtrList clients(factory()->clients()); QPtrListIterator clientsIt( clients ); for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt) { client = clientsIt.current(); ac = client->actionCollection(); actions = ac->actions(); end = actions.end(); begin = actions.begin(); for ( it = begin; it != end; ++it ) { if (QString((*it)->name()) == "options_show_menubar") m_showMenuBarAction = (KToggleAction*)(*it); if (QString((*it)->name()) == "fullscreen") m_showFullScreenAction = (KToggleAction*)(*it); } } } m_actionsSearched = true; } KPopupMenu *popup = new KPopupMenu( widget(), "rmb popup" ); if (page) { popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); if ( page->hasBookmark() ) popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 ); else popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 ); if ( m_pageView->canFitPageWidth() ) popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 ); //popup->insertItem( SmallIcon("view_fit_width"), i18n("Zoom this"), 2 ); //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 ); //popup->setItemEnabled( 3, false ); reallyShow = true; } /* //Albert says: I have not ported this as i don't see it does anything if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ... { m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image..."), 4 ); m_popup->setItemEnabled( 4, false ); }*/ if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked())) { popup->insertTitle( i18n( "Tools" ) ); if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup); if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup); reallyShow = true; } if (reallyShow) { switch ( popup->exec(point) ) { case 1: m_document->toggleBookmark( page->number() ); break; case 2: m_pageView->fitPageWidth( page->number() ); break; // case 3: // switch to edit mode // break; } } delete popup; } void Part::slotShowProperties() { PropertiesDialog *d = new PropertiesDialog(widget(), m_document); d->exec(); delete d; } void Part::slotShowPresentation() { if ( !m_presentationWidget ) m_presentationWidget = new PresentationWidget( widget(), m_document ); } void Part::slotHidePresentation() { if ( m_presentationWidget ) delete (PresentationWidget*) m_presentationWidget; } void Part::slotPrint() { if (m_document->pages() == 0) return; double width, height; int landscape, portrait; KPrinter printer; const KPDFPage *page; printer.setPageSelection(KPrinter::ApplicationSide); printer.setMinMax(1, m_document->pages()); printer.setCurrentPage(m_document->currentPage()+1); printer.setMargins(0, 0, 0, 0); // if some pages are landscape and others are not the most common win as kprinter does // not accept a per page setting landscape = 0; portrait = 0; for (uint i = 0; i < m_document->pages(); i++) { page = m_document->page(i); width = page->width(); height = page->height(); if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height); if (width > height) landscape++; else portrait++; } if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); if ( m_document->canConfigurePrinter() ) doPrint( printer ); else if (printer.setup(widget())) doPrint( printer ); } void Part::doPrint(KPrinter &printer) { if (!m_document->isAllowed(KPDFDocument::AllowPrint)) { KMessageBox::error(widget(), i18n("Printing this document is not allowed.")); return; } if (!m_document->print(printer)) { KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.kde.org")); } } void Part::restoreDocument(const KURL &url, int page) { if (openURL(url)) goToPage(page); } void Part::saveDocumentRestoreInfo(KConfig* config) { config->writePathEntry( "URL", url().url() ); if (m_document->pages() > 0) config->writeEntry( "Page", m_document->currentPage() + 1 ); } void Part::psTransformEnded() { m_file = m_temporaryLocalFile; openFile(); } /* * BrowserExtension class */ BrowserExtension::BrowserExtension(Part* parent) : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" ) { emit enableAction("print", true); setURLDropHandlingEnabled(true); } void BrowserExtension::print() { static_cast(parent())->slotPrint(); } #include "part.moc"