diff --git a/conf/settings.kcfgc b/conf/settings.kcfgc index 9064d15e3..f6e17ad78 100644 --- a/conf/settings.kcfgc +++ b/conf/settings.kcfgc @@ -4,6 +4,7 @@ File=okular.kcfg Inherits=SettingsCore Mutators=true Singleton=true -IncludeFiles=settings_core.h +Visibility=OKULAR_PART_EXPORT +IncludeFiles=settings_core.h,okular_part_export.h SourceIncludeFiles=kstandarddirs.h,qdom.h MemberVariables=dpointer diff --git a/core/document.cpp b/core/document.cpp index 921a7e81b..99e05630e 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -2105,6 +2105,26 @@ private: const KMimeType::Ptr &_mime; }; +QString DocumentPrivate::docDataFileName(const KUrl &url, qint64 document_size) +{ + QString fn = url.fileName(); + fn = QString::number( document_size ) + '.' + fn + ".xml"; + QString newokular = "okular/docdata/" + fn; + QString newokularfile = KStandardDirs::locateLocal( "data", newokular ); + if ( !QFile::exists( newokularfile ) ) + { + QString oldkpdf = "kpdf/" + fn; + QString oldkpdffile = KStandardDirs::locateLocal( "data", oldkpdf ); + if ( QFile::exists( oldkpdffile ) ) + { + // ### copy or move? + if ( !QFile::copy( oldkpdffile, newokularfile ) ) + return QString(); + } + } + return newokularfile; +} + Document::OpenResult Document::openDocument( const QString & docFile, const KUrl& url, const KMimeType::Ptr &_mime, const QString & password ) { KMimeType::Ptr mime = _mime; @@ -2129,23 +2149,8 @@ Document::OpenResult Document::openDocument( const QString & docFile, const KUrl d->m_docFileName = docFile; if ( url.isLocalFile() && !d->m_archiveData ) { - QString fn = url.fileName(); document_size = fileReadTest.size(); - fn = QString::number( document_size ) + '.' + fn + ".xml"; - QString newokular = "okular/docdata/" + fn; - QString newokularfile = KStandardDirs::locateLocal( "data", newokular ); - if ( !QFile::exists( newokularfile ) ) - { - QString oldkpdf = "kpdf/" + fn; - QString oldkpdffile = KStandardDirs::locateLocal( "data", oldkpdf ); - if ( QFile::exists( oldkpdffile ) ) - { - // ### copy or move? - if ( !QFile::copy( oldkpdffile, newokularfile ) ) - return OpenError; - } - } - d->m_xmlFileName = newokularfile; + d->m_xmlFileName = DocumentPrivate::docDataFileName(url, document_size); } } else diff --git a/core/document_p.h b/core/document_p.h index aabd192f5..08775da4c 100644 --- a/core/document_p.h +++ b/core/document_p.h @@ -136,6 +136,7 @@ class DocumentPrivate bool canModifyExternalAnnotations() const; bool canRemoveExternalAnnotations() const; void warnLimitedAnnotSupport(); + OKULAR_EXPORT static QString docDataFileName(const KUrl &url, qint64 document_size); // Methods that implement functionality needed by undo commands void performAddPageAnnotation( int page, Annotation *annotation ); diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 521a21678..d51cc7e6e 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -17,6 +17,7 @@ endif(KActivities_FOUND) set(okular_SRCS main.cpp + okular_main.cpp shell.cpp shellutils.cpp ) diff --git a/shell/main.cpp b/shell/main.cpp index 61e211319..16289608f 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -15,111 +15,10 @@ #include "shell.h" #include #include -#include -#include -#include -#include #include "aboutdata.h" +#include "okular_main.h" #include "shellutils.h" -static bool attachUniqueInstance(KCmdLineArgs* args) -{ - if (!args->isSet("unique") || args->count() != 1) - return false; - - QDBusInterface iface("org.kde.okular", "/okular", "org.kde.okular"); - QDBusInterface iface2("org.kde.okular", "/okularshell", "org.kde.okular"); - if (!iface.isValid() || !iface2.isValid()) - return false; - - if (args->isSet("print")) - iface.call("enableStartWithPrint"); - if (args->isSet("page")) - iface.call("openDocument", ShellUtils::urlFromArg(args->arg(0), ShellUtils::qfileExistFunc(), args->getOption("page")).url()); - else - iface.call("openDocument", ShellUtils::urlFromArg(args->arg(0), ShellUtils::qfileExistFunc()).url()); - if (args->isSet("raise")) { - iface2.call("tryRaise"); - } - - return true; -} - -// Ask an existing non-unique instance to open new tabs -static bool attachExistingInstance( KCmdLineArgs* args ) -{ - if ( args->count() < 1 ) - return false; - - const QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); - - // Don't match the service without trailing "-" (unique instance) - const QString pattern = "org.kde.okular-"; - const QString myPid = QString::number( kapp->applicationPid() ); - QScopedPointer bestService; - const int desktop = KWindowSystem::currentDesktop(); - - // Select the first instance that isn't us (metric may change in future) - foreach ( const QString& service, services ) - { - if ( service.startsWith(pattern) && !service.endsWith( myPid ) ) - { - bestService.reset( new QDBusInterface(service, "/okularshell", "org.kde.okular") ); - - // Find a window that can handle our documents - const QDBusReply reply = bestService->call( "canOpenDocs", args->count(), desktop ); - if( reply.isValid() && reply.value() ) - break; - - bestService.reset(); - } - } - - if ( !bestService ) - return false; - - for( int i = 0; i < args->count(); ++i ) - { - QString arg = args->arg( i ); - - // Copy stdin to temporary file which can be opened by the existing - // window. The temp file is automatically deleted after it has been - // opened. Not sure if this behavior is safe on all platforms. - QScopedPointer tempFile; - if( arg == "-" ) - { - tempFile.reset( new QTemporaryFile ); - QFile stdinFile; - if( !tempFile->open() || !stdinFile.open(stdin,QIODevice::ReadOnly) ) - return false; - - const size_t bufSize = 1024*1024; - QScopedPointer > buf( new char[bufSize] ); - size_t bytes; - do - { - bytes = stdinFile.read( buf.data(), bufSize ); - tempFile->write( buf.data(), bytes ); - } while( bytes != 0 ); - - arg = tempFile->fileName(); - } - else - { - arg = args->url( i ).url(); - } - - // Returns false if it can't fit another document - const QDBusReply reply = bestService->call( "openDocument", arg ); - if( !reply.isValid() || !reply.value() ) - return false; - } - - bestService->call( "tryRaise" ); - - return true; -} - int main(int argc, char** argv) { KAboutData about = okularAboutData( "okular", I18N_NOOP( "Okular" ) ); @@ -141,37 +40,24 @@ int main(int argc, char** argv) if (app.isSessionRestored()) { RESTORE(Shell); - } else { + } + else + { // no session.. just start up normally - KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); - - // try to attach to existing session, unique or not - if (attachUniqueInstance(args) || attachExistingInstance(args)) + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + QStringList paths; + for ( int i = 0; i < args->count(); ++i ) + paths << args->arg(i); + Okular::Status status = Okular::main(paths, ShellUtils::serializeOptions(*args)); + switch (status) { - args->clear(); - return 0; - } - - if (args->isSet( "unique" ) && args->count() > 1) - { - QTextStream stream(stderr); - stream << i18n( "Error: Can't open more than one document with the --unique switch" ) << endl; - return -1; - } - else - { - Shell* shell = new Shell( args ); - shell->show(); - for ( int i = 0; i < args->count(); ) - { - if ( shell->openDocument( args->arg(i)) ) - ++i; - else - { - shell = new Shell( args ); - shell->show(); - } - } + case Okular::Error: + return -1; + case Okular::AttachedOtherProcess: + return 0; + case Okular::Success: + // Do nothing + break; } } diff --git a/shell/shell.cpp b/shell/shell.cpp index 55f4f1248..c113e5717 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -60,21 +59,11 @@ static const char *shouldShowMenuBarComingFromFullScreen = "shouldShowMenuBarComingFromFullScreen"; static const char *shouldShowToolBarComingFromFullScreen = "shouldShowToolBarComingFromFullScreen"; -Shell::Shell(KCmdLineArgs* args, int argIndex) - : KParts::MainWindow(), m_args(args), m_menuBarWasShown(true), m_toolBarWasShown(true) +Shell::Shell( const QString &serializedOptions ) + : KParts::MainWindow(), m_menuBarWasShown(true), m_toolBarWasShown(true) #ifdef KActivities_FOUND , m_activityResource(0) #endif -{ - if (m_args && argIndex != -1) - { - m_openUrl = ShellUtils::urlFromArg(m_args->arg(argIndex), - ShellUtils::qfileExistFunc(), m_args->getOption("page")); - } - init(); -} - -void Shell::init() { setObjectName( QLatin1String( "okular::Shell" ) ); setContextMenuPolicy( Qt::NoContextMenu ); @@ -125,22 +114,19 @@ void Shell::init() readSettings(); - m_unique = false; - if (m_args && m_args->isSet("unique") && m_args->count() <= 1) + m_unique = ShellUtils::unique(serializedOptions); + if (m_unique) { m_unique = QDBusConnection::sessionBus().registerService("org.kde.okular"); if (!m_unique) KMessageBox::information(this, i18n("There is already a unique Okular instance running. This instance won't be the unique one.")); } - - if (m_args && !m_args->isSet("raise")) + if (ShellUtils::noRaise(serializedOptions)) { setAttribute(Qt::WA_ShowWithoutActivating); } QDBusConnection::sessionBus().registerObject("/okularshell", this, QDBusConnection::ExportScriptableSlots); - - if (m_openUrl.isValid()) QTimer::singleShot(0, this, SLOT(delayedOpen())); } else { @@ -148,11 +134,6 @@ void Shell::init() } } -void Shell::delayedOpen() -{ - openUrl( m_openUrl ); -} - void Shell::showOpenRecentMenu() { m_recent->menu()->popup(QCursor::pos()); @@ -168,13 +149,13 @@ Shell::~Shell() it->part->closeUrl( false ); } } - if ( m_args ) - m_args->clear(); + if (m_unique) + QDBusConnection::sessionBus().unregisterService("org.kde.okular"); } // Open a new document if we have space for it // This can hang if called on a unique instance and openUrl pops a messageBox -bool Shell::openDocument( const QString& doc ) +bool Shell::openDocument( const QString& url, const QString &serializedOptions ) { if( m_tabs.size() <= 0 ) return false; @@ -182,11 +163,14 @@ bool Shell::openDocument( const QString& doc ) KParts::ReadWritePart* const part = m_tabs[0].part; // Return false if we can't open new tabs and the only part is occupied - if( !dynamic_cast(part)->openNewFilesInTabs() - && !part->url().isEmpty() ) + if ( !dynamic_cast(part)->openNewFilesInTabs() + && !part->url().isEmpty() + && !ShellUtils::unique(serializedOptions)) + { return false; + } - openUrl( ShellUtils::urlFromArg(doc,ShellUtils::qfileExistFunc()) ); + openUrl( url, serializedOptions ); return true; } @@ -209,7 +193,7 @@ bool Shell::canOpenDocs( int numDocs, int desktop ) return true; } -void Shell::openUrl( const KUrl & url ) +void Shell::openUrl( const KUrl & url, const QString &serializedOptions ) { const int activeTab = m_tabWidget->currentIndex(); if ( activeTab < m_tabs.size() ) @@ -219,19 +203,19 @@ void Shell::openUrl( const KUrl & url ) { if( m_unique ) { - KMessageBox::error(this, i18n("Can't open more than one document in the unique Okular instance.")); + applyOptionsToPart( activePart, serializedOptions ); + activePart->openUrl( url ); } else { if( dynamic_cast(activePart)->openNewFilesInTabs() ) { - openNewTab( url ); - setActiveTab( m_tabs.size()-1 ); + openNewTab( url, serializedOptions ); } else { - Shell* newShell = new Shell(); - newShell->openUrl( url ); + Shell* newShell = new Shell( serializedOptions ); + newShell->openUrl( url, serializedOptions ); newShell->show(); } } @@ -239,13 +223,7 @@ void Shell::openUrl( const KUrl & url ) else { m_tabWidget->setTabText( activeTab, url.fileName() ); - if ( m_args ){ - KDocumentViewer* const doc = qobject_cast(activePart); - if ( doc && m_args->isSet( "presentation" ) ) - doc->startPresentation(); - if ( m_args->isSet( "print" ) ) - QMetaObject::invokeMethod( activePart, "enableStartWithPrint" ); - } + applyOptionsToPart( activePart, serializedOptions ); bool openOk = activePart->openUrl( url ); const bool isstdin = url.fileName( KUrl::ObeyTrailingSlash ) == QLatin1String( "-" ); if ( !isstdin ) @@ -525,7 +503,7 @@ void Shell::closeTab( int tab ) } -void Shell::openNewTab( const KUrl& url ) +void Shell::openNewTab( const KUrl& url, const QString &serializedOptions ) { // Tabs are hidden when there's only one, so show it if( m_tabs.size() == 1 ) @@ -545,8 +523,24 @@ void Shell::openNewTab( const KUrl& url ) KParts::ReadWritePart* const part = m_tabs[newIndex].part; m_tabWidget->addTab( part->widget(), url.fileName() ); + applyOptionsToPart(part, serializedOptions); + + int previousActiveTab = m_tabWidget->currentIndex(); + setActiveTab( m_tabs.size() - 1 ); + if( part->openUrl(url) ) m_recent->addUrl( url ); + else + setActiveTab( previousActiveTab ); +} + +void Shell::applyOptionsToPart( QObject* part, const QString &serializedOptions ) +{ + KDocumentViewer* const doc = qobject_cast(part); + if ( ShellUtils::startInPresentation(serializedOptions) ) + doc->startPresentation(); + if ( ShellUtils::showPrintDialog(serializedOptions) ) + QMetaObject::invokeMethod( part, "enableStartWithPrint" ); } void Shell::connectPart( QObject* part ) diff --git a/shell/shell.h b/shell/shell.h index e540054f1..66788fa5a 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -21,7 +21,6 @@ #include -class KCmdLineArgs; class KRecentFilesAction; class KToggleAction; class KTabWidget; @@ -47,11 +46,13 @@ class Shell : public KParts::MainWindow Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.okular") + friend class MainShellTest; + public: /** * Constructor */ - explicit Shell(KCmdLineArgs* args = 0, int argIndex = -1); + explicit Shell( const QString &serializedOptions = QString() ); /** * Default Destructor @@ -63,7 +64,7 @@ public slots: void slotQuit(); Q_SCRIPTABLE Q_NOREPLY void tryRaise(); - Q_SCRIPTABLE bool openDocument( const QString& doc ); + Q_SCRIPTABLE bool openDocument( const QString& url, const QString &serializedOptions = QString() ); Q_SCRIPTABLE bool canOpenDocs( int numDocs, int desktop ); protected: @@ -92,8 +93,7 @@ private slots: void slotUpdateFullScreen(); void slotShowMenubar(); - void openUrl( const KUrl & url ); - void delayedOpen(); + void openUrl( const KUrl & url, const QString &serializedOptions = QString() ); void showOpenRecentMenu(); void closeUrl(); void print(); @@ -118,14 +118,13 @@ signals: private: void setupAccel(); void setupActions(); - void init(); QStringList fileFormats() const; - void openNewTab( const KUrl& url ); + void openNewTab( const KUrl& url, const QString &serializedOptions ); + void applyOptionsToPart( QObject* part, const QString &serializedOptions ); void connectPart( QObject* part ); int findTabIndex( QObject* sender ); private: - KCmdLineArgs* m_args; KPluginFactory* m_partFactory; KRecentFilesAction* m_recent; QStringList m_fileformats; @@ -136,7 +135,6 @@ private: KToggleAction* m_showMenuBarAction; bool m_menuBarWasShown, m_toolBarWasShown; bool m_unique; - KUrl m_openUrl; KTabWidget* m_tabWidget; KToggleAction* m_openInTab; diff --git a/shell/shellutils.cpp b/shell/shellutils.cpp index 26c682512..0dd737cf7 100644 --- a/shell/shellutils.cpp +++ b/shell/shellutils.cpp @@ -64,4 +64,71 @@ KUrl urlFromArg( const QString& _arg, FileExistFunc exist_func, const QString& p return url; } +QString serializeOptions(const KCmdLineArgs &args) +{ + const bool startInPresentation = args.isSet( "presentation" ); + const bool showPrintDialog = args.isSet( "print" ); + const bool unique = args.isSet("unique") && args.count() <= 1; + const bool noRaise = !args.isSet("raise"); + const QString page = args.getOption("page"); + + return serializeOptions(startInPresentation, showPrintDialog, unique, noRaise, page); +} + +QString serializeOptions(bool startInPresentation, bool showPrintDialog, bool unique, bool noRaise, const QString &page) +{ + return QString("%1:%2:%3:%4:%5").arg(startInPresentation).arg(showPrintDialog).arg(unique).arg(noRaise).arg(page); +} + +bool unserializeOptions(const QString &serializedOptions, bool *presentation, bool *print, bool *unique, bool *noraise, QString *page) +{ + const QStringList args = serializedOptions.split(":"); + if (args.count() == 5) + { + *presentation = args[0] == "1"; + *print = args[1] == "1"; + *unique = args[2] == "1"; + *noraise = args[3] == "1"; + *page = args[4]; + return true; + } + return false; +} + +bool startInPresentation(const QString &serializedOptions) +{ + bool result, dummy; + QString dummyString; + return unserializeOptions(serializedOptions, &result, &dummy, &dummy, &dummy, &dummyString) && result; +} + +bool showPrintDialog(const QString &serializedOptions) +{ + bool result, dummy; + QString dummyString; + return unserializeOptions(serializedOptions, &dummy, &result, &dummy, &dummy, &dummyString) && result; +} + +bool unique(const QString &serializedOptions) +{ + bool result, dummy; + QString dummyString; + return unserializeOptions(serializedOptions, &dummy, &dummy, &result, &dummy, &dummyString) && result; +} + +bool noRaise(const QString &serializedOptions) +{ + bool result, dummy; + QString dummyString; + return unserializeOptions(serializedOptions, &dummy, &dummy, &dummy, &result, &dummyString) && result; +} + +QString page(const QString &serializedOptions) +{ + QString result; + bool dummy; + unserializeOptions(serializedOptions, &dummy, &dummy, &dummy, &dummy, &result); + return result; +} + } diff --git a/shell/shellutils.h b/shell/shellutils.h index 6c0c228a9..d5518c344 100644 --- a/shell/shellutils.h +++ b/shell/shellutils.h @@ -14,6 +14,8 @@ #include +class KCmdLineArgs; + namespace ShellUtils { @@ -21,6 +23,14 @@ typedef bool (*FileExistFunc)( const QString& fileName ); FileExistFunc qfileExistFunc(); KUrl urlFromArg( const QString& _arg, FileExistFunc exist_func, const QString& pageArg = QString() ); +QString serializeOptions(const KCmdLineArgs &args); +QString serializeOptions(bool startInPresentation, bool showPrintDialog, bool unique, bool noRaise, const QString &page); +bool unserializeOptions(const QString &serializedOptions, bool *presentation, bool *print, bool *unique, bool *noraise, QString *page); +bool unique(const QString &serializedOptions); +bool noRaise(const QString &serializedOptions); +bool startInPresentation(const QString &serializedOptions); +bool showPrintDialog(const QString &serializedOptions); +QString page(const QString &serializedOptions); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3b3fbdd8e..7fdd0bed1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,7 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) + kde4_add_unit_test( shelltest shelltest.cpp ../shell/shellutils.cpp ) target_link_libraries( shelltest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY} ) @@ -32,3 +34,6 @@ target_link_libraries( modifyannotationpropertiestest ${KDE4_KDECORE_LIBS} ${QT_ kde4_add_unit_test( editformstest editformstest.cpp ) target_link_libraries( editformstest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTXML_LIBRARY} okularcore ) + +kde4_add_unit_test( mainshelltest mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ) +target_link_libraries( mainshelltest ${KDE4_KPARTS_LIBS} ${QT_QTTEST_LIBRARY} okularpart okularcore )