/*************************************************************************** * 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-2007 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 // 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/embeddedfilesdialog.h" #include "ui/propertiesdialog.h" #include "ui/presentationwidget.h" #include "ui/pagesizelabel.h" #include "ui/bookmarklist.h" #include "conf/preferencesdialog.h" #include "settings.h" #include "core/bookmarkmanager.h" #include "core/document.h" #include "core/generator.h" #include "core/page.h" #include "interfaces/configinterface.h" typedef KParts::GenericFactory okularPartFactory; K_EXPORT_COMPONENT_FACTORY(libokularpart, okularPartFactory) Part::Part(QWidget *parentWidget, QObject *parent, const QStringList & /*args*/ ) : KParts::ReadOnlyPart(parent), m_showMenuBarAction(0), m_showFullScreenAction(0), m_actionsSearched(false), m_searchStarted(false), m_cliPresentation(false) { QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots); // connect the started signal to tell the job the mimetypes we like connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *))); // load catalog for translation KGlobal::locale()->insertCatalog("okular"); m_tempfile= 0L; // create browser extension (for printing when embedded into browser) m_bExtension = new BrowserExtension(this); // we need an instance setComponentData(okularPartFactory::componentData()); // build the document m_document = new Okular::Document(); 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( openUrlFromDocument(const KUrl &) ) ); connect( m_document->bookmarkManager(), SIGNAL( openUrl(const KUrl &) ), this, SLOT( openUrlFromBookmarks(const KUrl &) ) ); connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); if ( parent && parent->metaObject()->indexOfSlot( SLOT( slotQuit() ) ) != -1 ) connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) ); else connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) ); // 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 ); 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 ); leftPanelLayout->setMargin( 0 ); m_splitter->setCollapsible( 0, true ); // widgets: [left toolbox/..] | [] m_toolBox = new QToolBox( m_leftPanel ); leftPanelLayout->addWidget( m_toolBox ); int tbIndex; // [left toolbox: Table of Contents] | [] m_toc = new TOC( m_toolBox, m_document ); connect( m_toc, SIGNAL( hasTOC( bool ) ), this, SLOT( enableTOC( bool ) ) ); tbIndex = m_toolBox->addItem( m_toc, KIcon(QApplication::isLeftToRight() ? "leftjust" : "rightjust"), i18n("Contents") ); m_toolBox->setItemToolTip( tbIndex, i18n("Contents") ); enableTOC( false ); // [left toolbox: Thumbnails and Bookmarks] | [] KVBox * 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( openUrlFromDocument( const KUrl & )) ); connect( m_thumbnailList, SIGNAL( rightClick(const Okular::Page *, const QPoint &) ), this, SLOT( slotShowMenu(const Okular::Page *, const QPoint &) ) ); tbIndex = m_toolBox->addItem( thumbsBox, KIcon("thumbnail"), i18n("Thumbnails") ); m_toolBox->setItemToolTip( tbIndex, i18n("Thumbnails") ); m_toolBox->setCurrentIndex( m_toolBox->indexOf( thumbsBox ) ); // [left toolbox: Reviews] | [] Reviews * reviewsWidget = new Reviews( m_toolBox, m_document ); m_toolBox->addItem( reviewsWidget, KIcon("pencil"), i18n("Reviews") ); // [left toolbox: Bookmarks] | [] BookmarkList * bookmarkList = new BookmarkList( m_document, m_toolBox ); connect( bookmarkList, SIGNAL( openUrl(const KUrl &) ), this, SLOT( openUrlFromDocument(const KUrl &) ) ); m_toolBox->addItem( bookmarkList, KIcon("bookmark"), i18n("Bookmarks") ); // widgets: [../miniBarContainer] | [] QWidget * miniBarContainer = new QWidget( m_leftPanel ); leftPanelLayout->addWidget( miniBarContainer ); QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer ); miniBarLayout->setMargin( 0 ); // widgets: [../[spacer/..]] | [] miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // widgets: [../[../MiniBar]] | [] QFrame * bevelContainer = new QFrame( miniBarContainer ); bevelContainer->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); QVBoxLayout * bevelContainerLayout = new QVBoxLayout( bevelContainer ); bevelContainerLayout->setMargin( 4 ); m_progressWidget = new ProgressWidget( bevelContainer, m_document ); bevelContainerLayout->addWidget( m_progressWidget ); miniBarLayout->addWidget( bevelContainer ); miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // widgets: [] | [right 'pageView'] QWidget * rightContainer = new QWidget( m_splitter ); QVBoxLayout * rightLayout = new QVBoxLayout( rightContainer ); rightLayout->setMargin( 0 ); rightLayout->setSpacing( 0 ); // KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" ); // rightLayout->addWidget( rtb ); m_topMessage = new PageViewTopMessage( rightContainer ); connect( m_topMessage, SIGNAL( action() ), this, SLOT( slotShowEmbeddedFiles() ) ); rightLayout->addWidget( m_topMessage ); m_pageView = new PageView( rightContainer, m_document ); m_pageView->setFocus(); //usability setting m_splitter->setFocusProxy(m_pageView); connect( m_pageView, SIGNAL( urlDropped( const KUrl& ) ), SLOT( openUrlFromDocument( const KUrl & ))); connect( m_pageView, SIGNAL( rightClick(const Okular::Page *, const QPoint &) ), this, SLOT( slotShowMenu(const Okular::Page *, const QPoint &) ) ); connect( m_document, SIGNAL( error( const QString&, int ) ), m_pageView, SLOT( errorMessage( const QString&, int ) ) ); connect( m_document, SIGNAL( warning( const QString&, int ) ), m_pageView, SLOT( warningMessage( const QString&, int ) ) ); connect( m_document, SIGNAL( notice( const QString&, int ) ), m_pageView, SLOT( noticeMessage( const QString&, int ) ) ); rightLayout->addWidget( m_pageView ); QWidget * bottomBar = new QWidget( rightContainer ); QHBoxLayout * bottomBarLayout = new QHBoxLayout( bottomBar ); m_pageSizeLabel = new PageSizeLabel( bottomBar, m_document ); bottomBarLayout->setMargin( 0 ); bottomBarLayout->setSpacing( 0 ); bottomBarLayout->addWidget( m_pageSizeLabel->antiWidget() ); bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) ); m_miniBar = new MiniBar( bottomBar, m_document ); bottomBarLayout->addWidget( m_miniBar ); bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) ); bottomBarLayout->addWidget( m_pageSizeLabel ); rightLayout->addWidget( bottomBar ); connect( reviewsWidget, SIGNAL( setAnnotationWindow( Okular::Annotation* ) ), m_pageView, SLOT( setAnnotationWindow( Okular::Annotation* ) ) ); connect( reviewsWidget, SIGNAL( removeAnnotationWindow( Okular::Annotation* ) ), m_pageView, SLOT( removeAnnotationWindow( Okular::Annotation* ) ) ); // add document observers m_document->addObserver( this ); m_document->addObserver( m_thumbnailList ); m_document->addObserver( m_pageView ); m_document->addObserver( m_toc ); m_document->addObserver( m_miniBar ); m_document->addObserver( m_progressWidget ); m_document->addObserver( reviewsWidget ); m_document->addObserver( m_pageSizeLabel ); m_document->addObserver( bookmarkList ); // ACTIONS KActionCollection * ac = actionCollection(); // Page Traversal actions m_gotoPage = KStandardAction::gotoPage( this, SLOT( slotGoToPage() ), ac ); ac->addAction("goto_page", m_gotoPage); m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_G) ); // dirty way to activate gotopage when pressing miniBar's button connect( m_miniBar, SIGNAL( gotoPage() ), m_gotoPage, SLOT( trigger() ) ); m_prevPage = KStandardAction::prior(this, SLOT(slotPreviousPage()), ac); ac->addAction("previous_page", m_prevPage); m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); m_prevPage->setShortcut( 0 ); // dirty way to activate prev page when pressing miniBar's button connect( m_miniBar, SIGNAL( prevPage() ), m_prevPage, SLOT( trigger() ) ); connect( m_progressWidget, SIGNAL( prevPage() ), m_prevPage, SLOT( trigger() ) ); m_nextPage = KStandardAction::next(this, SLOT(slotNextPage()), ac ); ac->addAction("next_page", m_nextPage); m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); m_nextPage->setShortcut( 0 ); // dirty way to activate next page when pressing miniBar's button connect( m_miniBar, SIGNAL( nextPage() ), m_nextPage, SLOT( trigger() ) ); connect( m_progressWidget, SIGNAL( nextPage() ), m_nextPage, SLOT( trigger() ) ); m_firstPage = KStandardAction::firstPage( this, SLOT( slotGotoFirst() ), ac ); ac->addAction("first_page", m_firstPage); m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); m_lastPage = KStandardAction::lastPage( this, SLOT( slotGotoLast() ), ac ); ac->addAction("last_page",m_lastPage); m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); m_historyBack = KStandardAction::back( this, SLOT( slotHistoryBack() ), ac ); ac->addAction("history_back",m_historyBack); m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) ); m_historyNext = KStandardAction::forward( this, SLOT( slotHistoryNext() ), ac); ac->addAction("history_forward",m_historyNext); m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) ); m_prevBookmark = ac->addAction("previous_bookmark"); m_prevBookmark->setText(i18n( "Previous Bookmark" )); m_prevBookmark->setIcon(KIcon( "previous" )); m_prevBookmark->setWhatsThis( i18n( "Go to the previous bookmarked page" ) ); connect( m_prevBookmark, SIGNAL( triggered() ), this, SLOT( slotPreviousBookmark() ) ); m_nextBookmark = ac->addAction("next_bookmark"); m_nextBookmark->setText(i18n( "Next Bookmark" )); m_nextBookmark->setIcon(KIcon( "next" )); m_nextBookmark->setWhatsThis( i18n( "Go to the next bookmarked page" ) ); connect( m_nextBookmark, SIGNAL( triggered() ), this, SLOT( slotNextBookmark() ) ); m_copy = KStandardAction::create( KStandardAction::Copy, m_pageView, SLOT( copyTextSelection() ), ac ); ac->addAction("edit_copy",m_copy); // Find and other actions m_find = KStandardAction::find( this, SLOT( slotFind() ), ac ); ac->addAction("find", m_find); m_find->setEnabled( false ); m_findNext = KStandardAction::findNext( this, SLOT( slotFindNext() ), ac); ac->addAction("find_next",m_findNext); m_findNext->setEnabled( false ); m_saveAs = KStandardAction::saveAs( this, SLOT( slotSaveFileAs() ), ac ); ac->addAction("save",m_saveAs); m_saveAs->setEnabled( false ); QAction * prefs = KStandardAction::preferences( this, SLOT( slotPreferences() ), ac); ac->addAction("preferences", prefs); if ( parent && ( parent->objectName() == QLatin1String( "okular::Shell" ) ) ) { prefs->setText( i18n( "Configure okular..." ) ); } else { // TODO: improve this message prefs->setText( i18n( "Configure Viewer..." ) ); } QAction * genPrefs = KStandardAction::preferences( this, SLOT( slotGeneratorPreferences() ), ac ); ac->addAction("generator_prefs", genPrefs); genPrefs->setText( i18n( "Configure Backends..." ) ); QString constraint("([X-KDE-Priority] > 0) and (exist Library) and ([X-KDE-okularHasInternalSettings])") ; KService::List gens = KServiceTypeTrader::self()->query("okular/Generator",constraint); if (gens.count() <= 0) { genPrefs->setEnabled( false ); } m_printPreview = KStandardAction::printPreview( this, SLOT( slotPrintPreview() ), ac ); m_printPreview->setEnabled( false ); m_showLeftPanel = ac->add("show_leftpanel"); m_showLeftPanel->setText(i18n( "Show &Navigation Panel")); m_showLeftPanel->setIcon(KIcon( "show_side_panel" )); connect( m_showLeftPanel, SIGNAL( toggled( bool ) ), this, SLOT( slotShowLeftPanel() ) ); m_showLeftPanel->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_L) ); m_showLeftPanel->setCheckedState( KGuiItem(i18n( "Hide &Navigation Panel" ) )); m_showLeftPanel->setChecked( Okular::Settings::showLeftPanel() ); slotShowLeftPanel(); QAction * importPS = ac->addAction("import_ps"); importPS->setText(i18n("&Import Postscript as PDF...")); importPS->setIcon(KIcon("psimport")); connect(importPS, SIGNAL(triggered()), this, SLOT(slotImportPSFile())); QAction * ghns = ac->addAction("get_new_stuff"); ghns->setText(i18n("&Get Books From Internet...")); ghns->setIcon(KIcon("knewstuff")); connect(ghns, SIGNAL(triggered()), this, SLOT(slotGetNewStuff())); // TEMP, REMOVE ME! ghns->setShortcut( Qt::Key_G ); m_showProperties = ac->addAction("properties"); m_showProperties->setText(i18n("&Properties")); m_showProperties->setIcon(KIcon("info")); connect(m_showProperties, SIGNAL(triggered()), this, SLOT(slotShowProperties())); m_showProperties->setEnabled( false ); m_showEmbeddedFiles = ac->addAction("embedded_files"); m_showEmbeddedFiles->setText(i18n("&Embedded Files")); connect(m_showEmbeddedFiles, SIGNAL(triggered()), this, SLOT(slotShowEmbeddedFiles())); m_showEmbeddedFiles->setEnabled( false ); m_showPresentation = ac->addAction("presentation"); m_showPresentation->setText(i18n("P&resentation")); m_showPresentation->setIcon(KIcon( "kpresenter_kpr" )); connect(m_showPresentation, SIGNAL(triggered()), this, SLOT(slotShowPresentation())); m_showPresentation->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) ); m_showPresentation->setEnabled( false ); m_exportAs = ac->addAction("file_export_as"); m_exportAs->setText(i18n("E&xport As")); QMenu *menu = new QMenu(widget()); connect(menu, SIGNAL(triggered(QAction *)), this, SLOT(slotExportAs(QAction *))); m_exportAs->setMenu( menu ); m_exportAsText = menu->addAction( KIcon( "text" ), i18n( "Text..." ) ); m_exportAsText->setEnabled( false ); // attach the actions of the children widgets too m_pageView->setupActions( ac ); // apply configuration (both internal settings and GUI configured items) QList splitterSizes = Okular::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 connect( m_splitter, SIGNAL( splitterMoved( int, int ) ), this, SLOT( splitterMoved( int, int ) ) ); // 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 ); m_dirtyHandler->setSingleShot( true ); connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); slotNewConfig(); // [SPEECH] check for KTTSD presence and usability KService::List offers = KServiceTypeTrader::self()->query("DBUS/Text-to-Speech", "Name == 'KTTSD'"); Okular::Settings::setUseKTTSD( !offers.isEmpty() ); Okular::Settings::writeConfig(); rebuildBookmarkMenu( false ); // set our XML-UI resource file setXMLFile("part.rc"); // updateViewActions(); } Part::~Part() { delete m_toc; delete m_pageView; delete m_thumbnailList; delete m_miniBar; delete m_progressWidget; delete m_pageSizeLabel; delete m_document; delete m_tempfile; qDeleteAll( m_bookmarkActions ); } bool Part::openDocument(const KUrl& url, uint page) { Okular::DocumentViewport vp( page - 1 ); if ( vp.isValid() ) m_document->setNextDocumentViewport( vp ); return openUrl( url ); } void Part::startPresentation() { m_cliPresentation = true; } void Part::openUrlFromDocument(const KUrl &url) { m_bExtension->openUrlNotify(); m_bExtension->setLocationBarUrl(url.prettyUrl()); openUrl(url); } void Part::openUrlFromBookmarks(const KUrl &_url) { KUrl url = _url; Okular::DocumentViewport vp( _url.htmlRef() ); if ( vp.isValid() ) m_document->setNextDocumentViewport( vp ); url.setHTMLRef( QString() ); if ( m_document->currentDocument() == url ) { if ( vp.isValid() ) m_document->setViewport( vp ); } else openUrl( url ); } void Part::setMimeTypes(KIO::Job *job) { if (job) { QStringList supportedMimeTypes = m_document->supportedMimeTypes(); job->addMetaData("accept", supportedMimeTypes.join(", ") + ", */*;q=0.5"); connect(job, SIGNAL(mimetype(KIO::Job*,const QString&)), this, SLOT(readMimeType(KIO::Job*,const QString&))); } } void Part::readMimeType(KIO::Job *, const QString &mime) { m_jobMime = mime; } void Part::slotGeneratorPreferences( ) { // 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", Okular::Settings::self() ); dialog->setCaption( i18n( "Configure Backends" ) ); m_document->fillConfigDialog( dialog ); // (for now don't FIXME) keep us informed when the user changes settings // connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) ); dialog->show(); } void Part::notifySetup( const QVector< Okular::Page * > & /*pages*/, bool documentChanged ) { if ( !documentChanged ) return; rebuildBookmarkMenu(); } 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::notifyPageChanged( int /*page*/, int flags ) { if ( !(flags & Okular::DocumentObserver::Bookmark ) ) return; rebuildBookmarkMenu(); } 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("okularpart", I18N_NOOP("okular::Part"), "0.1"); aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org"); return aboutData; } bool Part::slotImportPSFile() { QString app = KStandardDirs::findExe( "ps2pdf" ); if ( app.isEmpty() ) { // TODO point the user to their distro packages? KMessageBox::error( widget(), i18n( "The program \"ps2pdf\" was not found, so okular can not import PS files using it." ), i18n("ps2pdf not found") ); return false; } KUrl url = KFileDialog::getOpenUrl( KUrl(), "application/postscript", this->widget() ); if ( url.isLocalFile() ) { KTemporaryFile tf; tf.setSuffix( ".pdf" ); tf.setAutoRemove( false ); if ( !tf.open() ) return false; m_temporaryLocalFile = tf.fileName(); tf.close(); m_file = url.path(); 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())); p -> start(); return true; } m_temporaryLocalFile.clear(); return false; } bool Part::openFile() { KMimeType::Ptr mime; if ( m_bExtension->urlArgs().serviceType.isEmpty() ) { if (!m_jobMime.isEmpty()) { mime = KMimeType::mimeType(m_jobMime); if ( !mime ) { mime = KMimeType::findByPath( m_file ); } } else { mime = KMimeType::findByPath( m_file ); } } else { mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType ); } bool ok = m_document->openDocument( m_file, url(), mime ); 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 ); bool hasEmbeddedFiles = ok && m_document->embeddedFiles() && m_document->embeddedFiles()->count() > 0; m_showEmbeddedFiles->setEnabled( hasEmbeddedFiles ); if ( hasEmbeddedFiles ) m_topMessage->display( i18n( "This document has embedded files. Click here to see them or go to File -> Embedded Files." ), KIcon( "attach" ) ); else m_topMessage->hide(); m_showPresentation->setEnabled( ok ); if ( ok ) { m_exportFormats = m_document->exportFormats(); QList::ConstIterator it = m_exportFormats.constBegin(); QList::ConstIterator itEnd = m_exportFormats.constEnd(); QMenu *menu = m_exportAs->menu(); for ( ; it != itEnd; ++it ) { const Okular::ExportFormat &format = *it; if ( !format.icon().isNull() ) { menu->addAction( format.icon(), format.description() ); } else { menu->addAction( format.description() ); } } } m_exportAsText->setEnabled( ok && m_document->canExportToText() ); // update viewing actions updateViewActions(); if ( !ok ) { // if can't open document, update windows so they display blank contents m_pageView->widget()->update(); m_thumbnailList->update(); return false; } // set the file to the fileWatcher if ( !m_watcher->contains(m_file) ) m_watcher->addFile(m_file); // if the 'OpenTOC' flag is set, start presentation if ( m_document->metaData( "OpenTOC" ).toBool() && m_toolBox->isItemEnabled( 0 ) ) { m_toolBox->setCurrentIndex( 0 ); } // if the 'StartFullScreen' flag is set, or the command line flag was // specified, start presentation if ( m_document->metaData( "StartFullScreen" ).toBool() || m_cliPresentation ) { if ( !m_cliPresentation ) KMessageBox::information( m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString::null, "autoPresentationWarning" ); m_cliPresentation = false; QMetaObject::invokeMethod(this, "slotShowPresentation", Qt::QueuedConnection); } /* 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 m_jobMime.clear(); const QString path = url.path(); const KMimeType::Ptr mimetype = KMimeType::findByPath( path ); bool isCompressedFile = false; KUrl tempUrl; if (( mimetype->name() == "application/x-gzip" ) || ( mimetype->name() == "application/x-bzip2" ) || ( mimetype->parentMimeType() == "application/x-gzip" ) || ( mimetype->parentMimeType() == "application/x-bzip2" ) ) { isCompressedFile=handleCompressed(tempUrl,path,mimetype); } // this calls in sequence the 'closeUrl' and 'openFile' methods bool openOk; if ( !isCompressedFile ) openOk = KParts::ReadOnlyPart::openUrl(url); else openOk = KParts::ReadOnlyPart::openUrl(tempUrl); if ( openOk ) { m_viewportDirty.pageNumber = -1; // if the document have a 'DocumentTitle' flag set (and it is not empty), set it as title QString title = m_document->metaData( "DocumentTitle" ).toString(); if ( !title.isEmpty() && !title.trimmed().isEmpty() ) { emit setWindowCaption( title ); } else { emit setWindowCaption( url.fileName() ); } } emit enablePrintAction(openOk); return openOk; } bool Part::closeUrl() { if (!m_temporaryLocalFile.isNull()) { QFile::remove( m_temporaryLocalFile ); m_temporaryLocalFile.clear(); } slotHidePresentation(); m_find->setEnabled( false ); m_findNext->setEnabled( false ); m_saveAs->setEnabled( false ); m_printPreview->setEnabled( false ); m_showProperties->setEnabled( false ); m_showEmbeddedFiles->setEnabled( false ); m_exportAsText->setEnabled( false ); m_exportFormats.clear(); QMenu *menu = m_exportAs->menu(); QList acts = menu->actions(); int num = acts.count(); for ( int i = 1; i < num; ++i ) { menu->removeAction( acts.at(i) ); delete acts.at(i); } m_showPresentation->setEnabled( false ); emit setWindowCaption(""); emit enablePrintAction(false); m_searchStarted = false; if (!m_file.isEmpty()) m_watcher->removeFile(m_file); m_document->closeDocument(); updateViewActions(); m_searchWidget->clearText(); return KParts::ReadOnlyPart::closeUrl(); } void Part::close() { if (parent() && (parent()->objectName() == QLatin1String("okular::Shell"))) { closeUrl(); } else KMessageBox::information( widget(), i18n( "This link points to a close document action that does not work when using the embedded viewer." ), QString::null, "warnNoCloseIfNotInOkular" ); } void Part::cannotQuit() { KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString::null, "warnNoQuitIfNotInOkular" ); } void Part::splitterMoved( int /*pos*/, int index ) { // if pageView has been resized, save splitter sizes if ( index == 1 ) saveSplitterSize(); } void Part::slotShowLeftPanel() { bool showLeft = m_showLeftPanel->isChecked(); Okular::Settings::setShowLeftPanel( showLeft ); Okular::Settings::writeConfig(); // show/hide left panel m_leftPanel->setVisible( showLeft ); // this needs to be hidden explicitly to disable thumbnails gen m_thumbnailList->setVisible( showLeft ); } void Part::saveSplitterSize() { Okular::Settings::setSplitterSizes( m_splitter->sizes() ); Okular::Settings::writeConfig(); } 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 ); } } void Part::slotDoFileDirty() { // do the following the first time the file is reloaded if ( m_viewportDirty.pageNumber == -1 ) { // store the current viewport m_viewportDirty = m_document->viewport(); // store if presentation view was open m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0); // 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 successful 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; if (m_wasPresentationOpen) slotShowPresentation(); emit enablePrintAction(true); } else { // start watching the file again (since we dropped it on close) m_watcher->addFile(m_file); m_dirtyHandler->start( 750 ); } } 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 GotoPageDialog : public KDialog { public: GotoPageDialog(QWidget *p, int current, int max) : KDialog(p) { setCaption(i18n("Go to Page")); setButtons(Ok | Cancel); setDefaultButton(Ok); QWidget *w = new QWidget(this); setMainWidget(w); QVBoxLayout *topLayout = new QVBoxLayout(w); topLayout->setMargin(0); topLayout->setSpacing(spacingHint()); e1 = new KIntNumInput(current, w); e1->setRange(1, max); e1->setEditFocus(true); QLabel *label = new QLabel(i18n("&Page:"), w); label->setBuddy(e1); topLayout->addWidget(label); topLayout->addWidget(e1); // A little bit extra space topLayout->addSpacing(spacingHint()); topLayout->addStretch(10); e1->setFocus(); } int getPage() const { return e1->value(); } protected: KIntNumInput *e1; }; //END go to page dialog void Part::slotGoToPage() { GotoPageDialog 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->isOpened() && !(m_document->currentPage() < 1) ) m_document->setViewportPage( m_document->currentPage() - 1 ); } void Part::slotNextPage() { if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) ) m_document->setViewportPage( m_document->currentPage() + 1 ); } void Part::slotGotoFirst() { if ( m_document->isOpened() ) m_document->setViewportPage( 0 ); } void Part::slotGotoLast() { if ( m_document->isOpened() ) m_document->setViewportPage( m_document->pages() - 1 ); } void Part::slotHistoryBack() { m_document->setPrevViewport(); } void Part::slotHistoryNext() { m_document->setNextViewport(); } void Part::slotPreviousBookmark() { uint current = m_document->currentPage(); // we are at the first page if ( current == 0 ) return; for ( int i = current - 1; i >= 0; --i ) { if ( m_document->isBookmarked( i ) ) { m_document->setViewportPage( i ); break; } } } void Part::slotNextBookmark() { uint current = m_document->currentPage(); uint pages = m_document->pages(); // we are at the last page if ( current == pages ) return; for ( uint i = current + 1; i < pages; ++i ) { if ( m_document->isBookmarked( i ) ) { m_document->setViewportPage( i ); break; } } } void Part::slotFind() { KFindDialog dlg( widget() ); dlg.setHasCursor( false ); if ( !m_searchHistory.empty() ) dlg.setFindHistory( m_searchHistory ); dlg.setSupportsBackwardsFind( false ); dlg.setSupportsWholeWordsFind( false ); dlg.setSupportsRegularExpressionFind( false ); if ( dlg.exec() == QDialog::Accepted ) { m_searchHistory = dlg.findHistory(); m_searchStarted = true; m_document->resetSearch( PART_SEARCH_ID ); m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, dlg.options() & KFind::CaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, Okular::Document::NextMatch, true, qRgb( 255, 255, 64 ) ); } } void Part::slotFindNext() { if (!m_document->continueLastSearch()) 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::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", saveUrl.fileName()), QString::null, KGuiItem(i18n("Overwrite"))) != KMessageBox::Continue) 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.", saveUrl.prettyUrl() ) ); } } void Part::slotGetNewStuff() { // show the modal dialog over pageview and execute it NewStuffDialog * dialog = new NewStuffDialog( m_pageView ); connect ( dialog , SIGNAL ( loadItemClicked( const KUrl & ) ), this , SLOT ( openUrlFromDocument ( const KUrl & ) ) ); 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, Okular::Settings::self() ); // keep us informed when the user changes settings connect( dialog, SIGNAL( settingsChanged( const QString & ) ), 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 = Okular::Settings::watchFile(); if ( watchFile && m_watcher->isStopped() ) m_watcher->startScan(); if ( !watchFile && !m_watcher->isStopped() ) { m_dirtyHandler->stop(); m_watcher->stopScan(); } bool showSearch = Okular::Settings::showSearchBar(); if ( !m_searchWidget->isHidden() != showSearch ) m_searchWidget->setVisible( showSearch ); // Main View (pageView) m_pageView->reparseConfig(); // update document settings m_document->reparseConfig(); // update TOC settings if ( m_toolBox->isItemEnabled(0) ) m_toc->reparseConfig(); // update ThumbnailList contents if ( Okular::Settings::showLeftPanel() && !m_thumbnailList->isHidden() ) m_thumbnailList->updateWidgets(); } void Part::slotPrintPreview() { if (m_document->pages() == 0) return; double width, height; int landscape, portrait; KPrinter printer; const Okular::Page *page; printer.setMinMax(1, m_document->pages()); printer.setPreviewOnly( true ); // 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->orientation() == 90 || page->orientation() == 270) qSwap(width, height); if (width > height) landscape++; else portrait++; } if (landscape > portrait) { // printer.setOption("orientation-requested", "4"); printer.setOrientation(KPrinter::Landscape); } doPrint(printer); } void Part::slotShowMenu(const Okular::Page *page, const QPoint &point) { bool reallyShow = false; if (!m_actionsSearched) { // the quest for options_show_menubar KActionCollection *ac; QAction *act; if (factory()) { QList clients(factory()->clients()); for(int i = 0 ; (!m_showMenuBarAction || !m_showFullScreenAction) && i < clients.size(); ++i) { ac = clients.at(i)->actionCollection(); // show_menubar act = ac->action("options_show_menubar"); if (act && qobject_cast(act)) m_showMenuBarAction = qobject_cast(act); // fullscreen act = ac->action("fullscreen"); if (act && qobject_cast(act)) m_showFullScreenAction = qobject_cast(act); } } m_actionsSearched = true; } KMenu *popup = new KMenu( widget() ); QAction *addBookmark = 0; QAction *removeBookmark = 0; QAction *fitPageWidth = 0; if (page) { popup->addTitle( i18n( "Page %1", page->number() + 1 ) ); if ( m_document->isBookmarked( page->number() ) ) removeBookmark = popup->addAction( KIcon("bookmark"), i18n("Remove Bookmark") ); else addBookmark = popup->addAction( KIcon("bookmark_add"), i18n("Add Bookmark") ); if ( m_pageView->canFitPageWidth() ) fitPageWidth = popup->addAction( KIcon("viewmagfit"), i18n("Fit Width") ); //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 ); //popup->setItemEnabled( 3, false ); popup->addAction( m_prevBookmark ); popup->addAction( m_nextBookmark ); 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->addTitle( i18n( "Tools" ) ); if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) popup->addAction(m_showMenuBarAction); if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) popup->addAction(m_showFullScreenAction); reallyShow = true; } if (reallyShow) { QAction *res = popup->exec(point); if (res) { if (res == addBookmark) m_document->addBookmark( page->number() ); else if (res == removeBookmark) m_document->removeBookmark( page->number() ); else if (res == fitPageWidth) m_pageView->fitPageWidth( page->number() ); } } delete popup; } void Part::slotShowProperties() { PropertiesDialog *d = new PropertiesDialog(widget(), m_document); d->exec(); delete d; } void Part::slotShowEmbeddedFiles() { EmbeddedFilesDialog *d = new EmbeddedFilesDialog(widget(), m_document); d->exec(); delete d; } void Part::slotShowPresentation() { if ( !m_presentationWidget ) { m_presentationWidget = new PresentationWidget( widget(), m_document ); m_presentationWidget->setupActions( actionCollection() ); } } void Part::slotHidePresentation() { if ( m_presentationWidget ) delete (PresentationWidget*) m_presentationWidget; } void Part::slotExportAs(QAction * act) { QList acts = m_exportAs->menu() ? m_exportAs->menu()->actions() : QList(); int id = acts.indexOf( act ); if ( ( id < 0 ) || ( id >= acts.count() ) ) return; QString filter = id == 0 ? "text/plain" : m_exportFormats.at( id - 1 ).mimeType()->name(); QString fileName = KFileDialog::getSaveFileName( url().isLocalFile() ? url().fileName() : QString::null, filter, widget() ); if ( !fileName.isEmpty() ) { bool saved = id == 0 ? m_document->exportToText( fileName ) : m_document->exportTo( fileName, m_exportFormats.at( id - 1 ) ); if ( !saved ) KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName ) ); } } void Part::slotPrint() { if (m_document->pages() == 0) return; double width, height; int landscape, portrait; KPrinter printer; const Okular::Page *page; printer.setPageSelection(KPrinter::ApplicationSide); printer.setMinMax(1, m_document->pages()); printer.setCurrentPage(m_document->currentPage()+1); // 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->orientation() == 90 || page->orientation() == 270) qSwap(width, height); if (width > height) landscape++; else portrait++; } if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); // range detecting QString range; uint pages = m_document->pages(); int startId = -1; int endId = -1; for ( uint i = 0; i < pages; ++i ) { if ( m_document->isBookmarked( i ) ) { if ( startId < 0 ) startId = i; if ( endId < 0 ) endId = startId; else ++endId; } else if ( startId >= 0 && endId >= 0 ) { if ( !range.isEmpty() ) range += ','; if ( endId - startId > 0 ) range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); else range += QString::number( startId + 1 ); startId = -1; endId = -1; } } if ( startId >= 0 && endId >= 0 ) { if ( !range.isEmpty() ) range += ','; if ( endId - startId > 0 ) range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); else range += QString::number( startId + 1 ); } printer.setOption( "kde-range", range ); if ( m_document->canConfigurePrinter() ) { KPrintDialogPage * w = m_document->printConfigurationWidget(); if ( w ) { printer.addDialogPage( w ); } } if ( printer.setup( widget() ) ) doPrint( printer ); } void Part::doPrint(KPrinter &printer) { if (!m_document->isAllowed(Okular::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(KConfig* config) { KUrl url ( config->readPathEntry( "URL" ) ); if ( url.isValid() ) { QString viewport = config->readEntry( "Viewport" ); if (!viewport.isEmpty()) m_document->setNextDocumentViewport( Okular::DocumentViewport( viewport ) ); openUrl( url ); } } void Part::saveDocumentRestoreInfo(KConfig* config) { config->writePathEntry( "URL", url().url() ); config->writeEntry( "Viewport", m_document->viewport().toString() ); } void Part::psTransformEnded() { m_file = m_temporaryLocalFile; openFile(); } bool Part::handleCompressed(KUrl & url, const QString &path, const KMimeType::Ptr mimetype) { // we are working with a compressed file, decompressing // temporary file for decompressing m_tempfile = new KTemporaryFile; if ( !m_tempfile ) { KMessageBox::error( 0, i18n("File Error! Could not create " "temporary file.")); return false; } m_tempfile->setAutoRemove(true); if ( ! m_tempfile->open() ) { KMessageBox::error( 0, i18n("File Error! Could not create temporary file " "%1.", strerror(m_tempfile->error()))); delete m_tempfile; return false; } // decompression filer QIODevice* filterDev; if (( mimetype->parentMimeType() == "application/x-gzip" ) || ( mimetype->parentMimeType() == "application/x-bzip2" )) filterDev = KFilterDev::deviceForFile(path, mimetype->parentMimeType()); else filterDev = KFilterDev::deviceForFile(path); if (!filterDev) { delete m_tempfile; return false; } if ( !filterDev->open(QIODevice::ReadOnly) ) { KMessageBox::detailedError( 0, i18n("File Error! Could not open the file " "%1 for uncompression. " "The file will not be loaded.", path), i18n("This error typically occurs if you do " "not have enough permissions to read the file. " "You can check ownership and permissions if you " "right-click on the file in the Konqueror " "file manager and then choose the 'Properties' menu.")); delete filterDev; delete m_tempfile; return false; } QByteArray buf(1024, '\0'); int read = 0, wrtn = 0; while ((read = filterDev->read(buf.data(), buf.size())) > 0) { wrtn = m_tempfile->write(buf.data(), read); if ( read != wrtn ) break; } delete filterDev; if ((read != 0) || (m_tempfile->size() == 0)) { KMessageBox::detailedError(0, i18n("File Error! Could not uncompress " "the file %1. " "The file will not be loaded.", path ), i18n("This error typically occurs if the file is corrupt. " "If you want to be sure, try to decompress the file manually " "using command-line tools.")); delete m_tempfile; return false; } url=m_tempfile->fileName(); return true; } void Part::rebuildBookmarkMenu( bool unplugActions ) { if ( unplugActions ) { unplugActionList( "bookmarks_currentdocument" ); qDeleteAll( m_bookmarkActions ); m_bookmarkActions.clear(); } KUrl u = m_document->currentDocument(); if ( u.isValid() ) { m_bookmarkActions = m_document->bookmarkManager()->actionsForUrl( u ); } bool havebookmarks = true; if ( m_bookmarkActions.isEmpty() ) { havebookmarks = false; QAction * a = new QAction( 0 ); a->setText( i18n( "No Bookmarks" ) ); a->setEnabled( false ); m_bookmarkActions.append( a ); } for ( int i = 0; i < m_bookmarkActions.count(); ++i ) { actionCollection()->addAction( QString( "bookmark_action_%1" ).arg( i ), m_bookmarkActions.at(i) ); } plugActionList( "bookmarks_currentdocument", m_bookmarkActions ); m_prevBookmark->setEnabled( havebookmarks ); m_nextBookmark->setEnabled( havebookmarks ); } /* * BrowserExtension class */ BrowserExtension::BrowserExtension(Part* parent) : KParts::BrowserExtension( parent ) { emit enableAction("print", true); setURLDropHandlingEnabled(true); } void BrowserExtension::print() { static_cast(parent())->slotPrint(); } #include "part.moc"