Commit 61c830cb authored by Albert Astals Cid's avatar Albert Astals Cid

Pass the command line options properly when using tabs or unique instances

Use a QString to serialize the command line options other than urls to open so it can be easily passed around to every place that opens a new shell or tab or overrides the content in a unique instance.

BUGS: 334100
FIXED-IN: 4.14.0
REVIEW: 119595
parent 50f2019f
......@@ -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
......@@ -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
......
......@@ -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 );
......
......@@ -17,6 +17,7 @@ endif(KActivities_FOUND)
set(okular_SRCS
main.cpp
okular_main.cpp
shell.cpp
shellutils.cpp
)
......
......@@ -15,111 +15,10 @@
#include "shell.h"
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <klocale.h>
#include <QtDBus/qdbusinterface.h>
#include <QTextStream>
#include <kwindowsystem.h>
#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<QDBusInterface> 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<bool> 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<QTemporaryFile> 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<char,QScopedPointerArrayDeleter<char> > 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<bool> 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;
}
}
......
......@@ -25,7 +25,6 @@
#include <QtDBus/qdbusconnection.h>
#include <kaction.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kfiledialog.h>
#include <kpluginloader.h>
#include <kmessagebox.h>
......@@ -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<Okular::ViewerInterface*>(part)->openNewFilesInTabs()
&& !part->url().isEmpty() )
if ( !dynamic_cast<Okular::ViewerInterface*>(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<Okular::ViewerInterface *>(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<KDocumentViewer*>(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<KDocumentViewer*>(part);
if ( ShellUtils::startInPresentation(serializedOptions) )
doc->startPresentation();
if ( ShellUtils::showPrintDialog(serializedOptions) )
QMetaObject::invokeMethod( part, "enableStartWithPrint" );
}
void Shell::connectPart( QObject* part )
......
......@@ -21,7 +21,6 @@
#include <QtDBus/QtDBus>
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;
......
......@@ -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;
}
}
......@@ -14,6 +14,8 @@
#include <kurl.h>
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);
}
......
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 )
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment