From 9c98ac0f8b52b4005a272097078f1a396bd36d14 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 13 Mar 2015 23:26:08 +0100 Subject: [PATCH 1/6] Always release annotation on mouse release BUGS: 345082 FIXED-IN: KDE Applications 15.04 Beta 3 --- ui/pageview.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 2dd8cf1c6..85c12e97c 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -2274,6 +2274,15 @@ void PageView::mouseReleaseEvent( QMouseEvent * e ) d->leftClickTimer.stop(); + if ( d->mouseAnn ) + { + // Just finished to move the annotation + d->mouseAnn->setFlags( d->mouseAnn->flags() & ~Okular::Annotation::BeingMoved ); + d->document->translatePageAnnotation(d->mouseAnnPageNum, d->mouseAnn, Okular::NormalizedPoint( 0.0, 0.0 ) ); + setCursor( Qt::ArrowCursor ); + d->mouseAnn = 0; + } + // don't perform any mouse action when no document is shown.. if ( d->items.isEmpty() ) { @@ -2307,15 +2316,6 @@ void PageView::mouseReleaseEvent( QMouseEvent * e ) return; } - if ( d->mouseAnn ) - { - // Just finished to move the annotation - d->mouseAnn->setFlags( d->mouseAnn->flags() & ~Okular::Annotation::BeingMoved ); - d->document->translatePageAnnotation(d->mouseAnnPageNum, d->mouseAnn, Okular::NormalizedPoint( 0.0, 0.0 ) ); - setCursor( Qt::ArrowCursor ); - d->mouseAnn = 0; - } - bool leftButton = e->button() == Qt::LeftButton; bool rightButton = e->button() == Qt::RightButton; switch ( d->mouseMode ) From ded1e5486d587dbce90ee93e9a59f5a87a500edf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 13 Mar 2015 23:30:50 +0100 Subject: [PATCH 2/6] Do not release the annotation if we release the middle button --- ui/pageview.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 85c12e97c..57d4a1371 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -2274,7 +2274,10 @@ void PageView::mouseReleaseEvent( QMouseEvent * e ) d->leftClickTimer.stop(); - if ( d->mouseAnn ) + const bool leftButton = e->button() == Qt::LeftButton; + const bool rightButton = e->button() == Qt::RightButton; + + if ( d->mouseAnn && leftButton ) { // Just finished to move the annotation d->mouseAnn->setFlags( d->mouseAnn->flags() & ~Okular::Annotation::BeingMoved ); @@ -2316,8 +2319,6 @@ void PageView::mouseReleaseEvent( QMouseEvent * e ) return; } - bool leftButton = e->button() == Qt::LeftButton; - bool rightButton = e->button() == Qt::RightButton; switch ( d->mouseMode ) { case Okular::Settings::EnumMouseMode::Browse:{ From 4ab459790ba2dd101093a91b27e6bb78ba8d4c4e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 13 Mar 2015 23:44:29 +0100 Subject: [PATCH 3/6] Do not show RMB menus if we're dragging an annotation --- ui/pageview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 57d4a1371..1631d9327 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -2125,7 +2125,7 @@ void PageView::mousePressEvent( QMouseEvent * e ) d->leftClickTimer.start( QApplication::doubleClickInterval() + 10 ); } } - else if ( rightButton ) + else if ( rightButton && !d->mouseAnn ) { PageViewItem * pageItem = pickItemOnPoint( eventPos.x(), eventPos.y() ); if ( pageItem ) @@ -2414,7 +2414,7 @@ void PageView::mouseReleaseEvent( QMouseEvent * e ) #endif } } - else if ( rightButton ) + else if ( rightButton && !d->mouseAnn ) { if ( pageItem && pageItem == pageItemPressPos && ( (d->mousePressPos - e->globalPos()).manhattanLength() < QApplication::startDragDistance() ) ) From a77bbac299556df25e192053097764b3770d5af2 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 14 Mar 2015 16:10:09 +0100 Subject: [PATCH 4/6] Fix typo --- core/fileprinter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/fileprinter.h b/core/fileprinter.h index c7cd32aef..60df4148d 100644 --- a/core/fileprinter.h +++ b/core/fileprinter.h @@ -60,7 +60,7 @@ public: * @param documentOrientation the orientation stored in the document itself * @param fileDeletePolicy if the application or system deletes the file * @param pageSelectPolicy if the application or system selects the pages to print - * @param pageRange page range to print if SystemSlectsPages and user chooses Selection in Print Dialog + * @param pageRange page range to print if SystemSelectsPages and user chooses Selection in Print Dialog * * @returns Returns exit code: * -9 if lpr not found From 1cfb007b6339fa51c010fdd27e8de4838dadb5a5 Mon Sep 17 00:00:00 2001 From: Jonathan Doman Date: Mon, 16 Mar 2015 23:55:57 +0100 Subject: [PATCH 5/6] Fix session restore/save with multiple tabs BUGS: 335852 REVIEW: 122570 --- part.cpp | 20 ------- part.h | 2 - shell/main.cpp | 2 +- shell/shell.cpp | 46 +++++++++------- shell/shell.h | 13 +++-- tests/mainshelltest.cpp | 119 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 48 deletions(-) diff --git a/part.cpp b/part.cpp index 36438af1c..fbeda1e65 100644 --- a/part.cpp +++ b/part.cpp @@ -2744,26 +2744,6 @@ void Part::doPrint(QPrinter &printer) } } - -void Part::restoreDocument(const KConfigGroup &group) -{ - KUrl url ( group.readPathEntry( "URL", QString() ) ); - if ( url.isValid() ) - { - QString viewport = group.readEntry( "Viewport" ); - if (!viewport.isEmpty()) m_document->setNextDocumentViewport( Okular::DocumentViewport( viewport ) ); - openUrl( url ); - } -} - - -void Part::saveDocumentRestoreInfo(KConfigGroup &group) -{ - group.writePathEntry( "URL", url().url() ); - group.writeEntry( "Viewport", m_document->viewport().toString() ); -} - - void Part::psTransformEnded(int exit, QProcess::ExitStatus status) { Q_UNUSED( exit ) diff --git a/part.h b/part.h index 594eb4411..65ccac6c4 100644 --- a/part.h +++ b/part.h @@ -222,8 +222,6 @@ class OKULAR_PART_EXPORT Part : public KParts::ReadWritePart, public Okular::Doc public slots: // connected to Shell action (and browserExtension), not local one void slotPrint(); - void restoreDocument(const KConfigGroup &group); - void saveDocumentRestoreInfo(KConfigGroup &group); void slotFileDirty( const QString& ); void slotDoFileDirty(); void psTransformEnded(int, QProcess::ExitStatus); diff --git a/shell/main.cpp b/shell/main.cpp index 16289608f..cc3d39bb4 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -39,7 +39,7 @@ int main(int argc, char** argv) // see if we are starting with session management if (app.isSessionRestored()) { - RESTORE(Shell); + kRestoreMainWindows(); } else { diff --git a/shell/shell.cpp b/shell/shell.cpp index f7675fdc8..364d53a11 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -59,6 +59,9 @@ static const char *shouldShowMenuBarComingFromFullScreen = "shouldShowMenuBarComingFromFullScreen"; static const char *shouldShowToolBarComingFromFullScreen = "shouldShowToolBarComingFromFullScreen"; +static const char* const SESSION_URL_KEY = "Urls"; +static const char* const SESSION_TAB_KEY = "ActiveTab"; + Shell::Shell( const QString &serializedOptions ) : KParts::MainWindow(), m_menuBarWasShown(true), m_toolBarWasShown(true) #ifdef KActivities_FOUND @@ -66,7 +69,7 @@ Shell::Shell( const QString &serializedOptions ) #endif , m_isValid(true) { - setObjectName( QLatin1String( "okular::Shell" ) ); + setObjectName( QLatin1String( "okular::Shell#" ) ); setContextMenuPolicy( Qt::NoContextMenu ); // set the shell's ui resource file setXMLFile("shell.rc"); @@ -106,6 +109,7 @@ Shell::Shell( const QString &serializedOptions ) // then, setup our actions setupActions(); + connect( QCoreApplication::instance(), SIGNAL(aboutToQuit()), SLOT(deleteLater()) ); // and integrate the part's GUI with the shell's setupGUI(Keys | ToolBar | Save); createGUI(firstPart); @@ -156,6 +160,7 @@ Shell::~Shell() { it->part->closeUrl( false ); } + m_tabs.clear(); } if (m_unique) QDBusConnection::sessionBus().unregisterService("org.kde.okular"); @@ -321,19 +326,31 @@ void Shell::setupActions() void Shell::saveProperties(KConfigGroup &group) { - // the 'config' object points to the session managed - // config file. anything you write here will be available - // later when this app is restored - emit saveDocumentRestoreInfo(group); + // Gather lists of settings to preserve + QStringList urls; + for( int i = 0; i < m_tabs.size(); ++i ) + { + urls.append( m_tabs[i].part->url().url() ); + } + group.writePathEntry( SESSION_URL_KEY, urls ); + group.writeEntry( SESSION_TAB_KEY, m_tabWidget->currentIndex() ); } void Shell::readProperties(const KConfigGroup &group) { - // the 'config' object points to the session managed - // config file. this function is automatically called whenever - // the app is being restored. read in here whatever you wrote - // in 'saveProperties' - emit restoreDocument(group); + // Reopen documents based on saved settings + QStringList urls = group.readPathEntry( SESSION_URL_KEY, QStringList() ); + + while( !urls.isEmpty() ) + { + openUrl( urls.takeFirst() ); + } + + int desiredTab = group.readEntry( SESSION_TAB_KEY, 0 ); + if( desiredTab < m_tabs.size() ) + { + setActiveTab( desiredTab ); + } } QStringList Shell::fileFormats() const @@ -399,11 +416,6 @@ void Shell::fileOpen() } } -void Shell::slotQuit() -{ - close(); -} - void Shell::tryRaise() { KWindowSystem::forceActiveWindow( window()->effectiveWinId() ); @@ -553,8 +565,6 @@ void Shell::applyOptionsToPart( QObject* part, const QString &serializedOptions void Shell::connectPart( QObject* part ) { - connect( this, SIGNAL(restoreDocument(KConfigGroup)), part, SLOT(restoreDocument(KConfigGroup))); - connect( this, SIGNAL(saveDocumentRestoreInfo(KConfigGroup&)), part, SLOT(saveDocumentRestoreInfo(KConfigGroup&))); connect( part, SIGNAL(enablePrintAction(bool)), this, SLOT(setPrintEnabled(bool))); connect( part, SIGNAL(enableCloseAction(bool)), this, SLOT(setCloseEnabled(bool))); connect( part, SIGNAL(mimeTypeChanged(KMimeType::Ptr)), this, SLOT(setTabIcon(KMimeType::Ptr))); @@ -655,6 +665,4 @@ void Shell::moveTabData( int from, int to ) m_tabs.move( from, to ); } -#include "shell.moc" - /* kate: replace-tabs on; indent-width 4; */ diff --git a/shell/shell.h b/shell/shell.h index 224acfe02..3eaed1d87 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -67,8 +67,6 @@ public: bool isValid() const; public slots: - void slotQuit(); - Q_SCRIPTABLE Q_NOREPLY void tryRaise(); Q_SCRIPTABLE bool openDocument( const QString& url, const QString &serializedOptions = QString() ); Q_SCRIPTABLE bool canOpenDocs( int numDocs, int desktop ); @@ -86,6 +84,13 @@ protected: * with @ref saveProperties */ void readProperties(const KConfigGroup&); + + /** + * Expose internal functions for session restore testing + */ + void savePropertiesInternal(KConfig* config, int num) {KMainWindow::savePropertiesInternal(config,num);} + void readPropertiesInternal(KConfig* config, int num) {KMainWindow::readPropertiesInternal(config,num);} + void readSettings(); void writeSettings(); void setFullScreen( bool ); @@ -117,10 +122,6 @@ private slots: void handleTabDrop( QDropEvent* event ); void moveTabData( int from, int to ); -signals: - void restoreDocument(const KConfigGroup &group); - void saveDocumentRestoreInfo(KConfigGroup &group); - private: void setupAccel(); void setupActions(); diff --git a/tests/mainshelltest.cpp b/tests/mainshelltest.cpp index c5d7289d6..a044895c1 100644 --- a/tests/mainshelltest.cpp +++ b/tests/mainshelltest.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../shell/okular_main.h" #include "../shell/shell.h" @@ -73,10 +74,26 @@ private slots: void testFileRemembersPagePosition(); void test2FilesError_data(); void test2FilesError(); + void testSessionRestore_data(); + void testSessionRestore(); private: }; +QList getShells() +{ + QList shells; + foreach( KMainWindow* kmw, KMainWindow::memberList() ) + { + Shell* shell = qobject_cast( kmw ); + if( shell ) + { + shells.append( shell ); + } + } + return shells; +} + Shell *findShell(Shell *ignore = 0) { foreach (QWidget *widget, QApplication::topLevelWidgets()) @@ -467,6 +484,108 @@ void MainShellTest::test2FilesError() QVERIFY(!s); } +void MainShellTest::testSessionRestore_data() +{ + QTest::addColumn("paths"); + QTest::addColumn("options"); + QTest::addColumn("useTabsOpen"); + QTest::addColumn("useTabsRestore"); + + QStringList oneDocPaths( KDESRCDIR "data/file1.pdf" ); + QStringList twoDocPaths( oneDocPaths ); + twoDocPaths << KDESRCDIR "data/formSamples.pdf"; + + const QString options = ShellUtils::serializeOptions(false, false, false, false, QString()); + + QTest::newRow("1 doc, 1 window, tabs") << oneDocPaths << options << true << true; + QTest::newRow("2 docs, 1 window, tabs") << twoDocPaths << options << true << true; + QTest::newRow("2 docs, 2 windows, tabs") << twoDocPaths << options << false << true; + QTest::newRow("2 docs, 2 windows, no tabs") << twoDocPaths << options << false << false; + QTest::newRow("2 docs, 1 window, no tabs") << twoDocPaths << options << true << false; +} + +void MainShellTest::testSessionRestore() +{ + QFETCH( QStringList, paths ); + QFETCH( QString, options ); + QFETCH( bool, useTabsOpen ); + QFETCH( bool, useTabsRestore ); + + Okular::Settings::self()->setShellOpenFileInTabs( useTabsOpen ); + + Okular::Status status = Okular::main( paths, options ); + QCOMPARE( status, Okular::Success ); + + // Gather some information about the state + // Verify that the correct number of windows/tabs were opened + QList shells = getShells(); + QVERIFY( !shells.isEmpty() ); + int numDocs = 0; + foreach( Shell* shell, shells ) + { + QTest::qWaitForWindowShown( shell ); + numDocs += shell->m_tabs.size(); + } + + QCOMPARE( numDocs, paths.size() ); + QCOMPARE( shells.size(), useTabsOpen ? 1 : paths.size() ); + QTest::qWait( 100 ); + + // Simulate session shutdown. The actual shutdown path comes through + // QSessionManager XSMP handlers, then KApplication::commitData/saveState, + // then KMWSessionManager::commitData/saveState. Without simulating an X + // session manager, the best we can do here is to make a temporary Config + // and call KMainWindows save functions directly. + QTemporaryFile configFile; + QVERIFY( configFile.open() ); + + int numWindows = 0; + { // Scope for config so that we can reconstruct from file + KConfig config( configFile.fileName(), KConfig::SimpleConfig ); + foreach( Shell* shell, shells ) + { + shell->savePropertiesInternal( &config, ++numWindows ); + // Windows aren't necessarily closed on shutdown, but we'll use + // this as a way to trigger the destructor code, which is normally + // connected to the aboutToQuit signal + shell->close(); + } + } + + // Wait for shells to delete themselves. QTest::qWait doesn't do deferred + // deletions so we'll set up a full event loop to do that. + QEventLoop eventLoop; + QTimer::singleShot( 100, &eventLoop, SLOT(quit()) ); + eventLoop.exec( QEventLoop::AllEvents | QEventLoop::DeferredDeletion ); + shells = getShells(); + QVERIFY( shells.isEmpty() ); + + Okular::Settings::self()->setShellOpenFileInTabs( useTabsRestore ); + + // Simulate session restore. We can't call KMainWindow::restore() directly + // because it asks for info from the session manager, which doesn't know + // about our temporary config. But the logic here mostly mirrors restore(). + KConfig config( configFile.fileName(), KConfig::SimpleConfig ); + for( int i = 1; i <= numWindows; ++i ) + { + Shell* shell = new Shell; + shell->readPropertiesInternal( &config, i ); + shell->show(); + } + + // Verify that the restore state is reasonable + shells = getShells(); + QVERIFY( !shells.isEmpty() ); + numDocs = 0; + foreach( Shell* shell, shells ) + { + QTest::qWaitForWindowShown( shell ); + numDocs += shell->m_tabs.size(); + } + + QCOMPARE( numDocs, paths.size() ); + QCOMPARE( shells.size(), useTabsRestore ? numWindows : paths.size() ); +} QTEST_KDEMAIN( MainShellTest, GUI ) #include "mainshelltest.moc" From 1eafe4feb151c713e8f7747164348c25886480bf Mon Sep 17 00:00:00 2001 From: Saheb Preet Singh Date: Tue, 17 Mar 2015 00:20:11 +0100 Subject: [PATCH 6/6] New shortcut to resize window to fit page FIXED-IN: KDE Applications 15.08 BUGS: 326844 REVIEW: 115283 --- doc/index.docbook | 10 ++++++++++ part.cpp | 6 ++++++ part.h | 3 +++ shell/shell.cpp | 11 +++++++++++ shell/shell.h | 5 +++++ ui/pageview.cpp | 43 +++++++++++++++++++++++++++++++++++++++++-- ui/pageview.h | 2 ++ ui/sidebar.cpp | 9 +++++++++ ui/sidebar.h | 2 ++ 9 files changed, 89 insertions(+), 2 deletions(-) diff --git a/doc/index.docbook b/doc/index.docbook index 323784955..38fb7b9cb 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -949,6 +949,16 @@ Context menu actions like Rename Bookmarks etc.) + + Fit window to page + + The Fit window to page feature resizes the window so that it is exactly the same size as the page at the current zoom factor. + If the page doesn't completely fit on the screen, the window is enlarged so that the largest possible part of the page is shown. + + + This feature can be accessed by using the keyboard shortcut &Ctrl;J + + diff --git a/part.cpp b/part.cpp index fbeda1e65..5b03e56e1 100644 --- a/part.cpp +++ b/part.cpp @@ -455,6 +455,7 @@ m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentW connect( m_document, SIGNAL(warning(QString,int)), this, SLOT(warningMessage(QString,int)) ); connect( m_document, SIGNAL(notice(QString,int)), this, SLOT(noticeMessage(QString,int)) ); connect( m_document, SIGNAL(sourceReferenceActivated(const QString&,int,int,bool*)), this, SLOT(slotHandleActivatedSourceReference(const QString&,int,int,bool*)) ); + connect( m_pageView, SIGNAL(fitWindowToPage(QSize,QSize)), this, SIGNAL(fitWindowToPage(QSize,QSize)) ); rightLayout->addWidget( m_pageView ); m_findBar = new FindBar( m_document, rightContainer ); rightLayout->addWidget( m_findBar ); @@ -2806,6 +2807,11 @@ void Part::noticeMessage( const QString &message, int duration ) m_pageView->displayMessage( message, QString(), PageViewMessage::Info, duration ); } +void Part::moveSplitter(int sideWidgetSize) +{ + m_sidebar->moveSplitter( sideWidgetSize ); +} + void Part::unsetDummyMode() { diff --git a/part.h b/part.h index 65ccac6c4..9eebdb2cd 100644 --- a/part.h +++ b/part.h @@ -159,6 +159,7 @@ class OKULAR_PART_EXPORT Part : public KParts::ReadWritePart, public Okular::Doc void enableCloseAction(bool enable); void mimeTypeChanged(KMimeType::Ptr mimeType); void urlsDropped( const KUrl::List& urls ); + void fitWindowToPage( const QSize& pageViewPortSize, const QSize& pageSize ); protected: // reimplemented from KParts::ReadWritePart @@ -231,6 +232,8 @@ class OKULAR_PART_EXPORT Part : public KParts::ReadWritePart, public Okular::Doc void warningMessage( const QString &message, int duration = -1 ); void noticeMessage( const QString &message, int duration = -1 ); + void moveSplitter( const int sideWidgetSize ); + private: Document::OpenResult doOpenFile(const KMimeType::Ptr &mime, const QString &fileNameToOpen, bool *isCompressedFile); diff --git a/shell/shell.cpp b/shell/shell.cpp index 364d53a11..73559689b 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -565,10 +565,12 @@ void Shell::applyOptionsToPart( QObject* part, const QString &serializedOptions void Shell::connectPart( QObject* part ) { + connect( this, SIGNAL(moveSplitter(int)), part, SLOT(moveSplitter(int)) ); connect( part, SIGNAL(enablePrintAction(bool)), this, SLOT(setPrintEnabled(bool))); connect( part, SIGNAL(enableCloseAction(bool)), this, SLOT(setCloseEnabled(bool))); connect( part, SIGNAL(mimeTypeChanged(KMimeType::Ptr)), this, SLOT(setTabIcon(KMimeType::Ptr))); connect( part, SIGNAL(urlsDropped(KUrl::List)), this, SLOT(handleDroppedUrls(KUrl::List)) ); + connect( part, SIGNAL(fitWindowToPage(QSize,QSize)), this, SLOT(slotFitWindowToPage(QSize,QSize)) ); } void Shell::print() @@ -665,4 +667,13 @@ void Shell::moveTabData( int from, int to ) m_tabs.move( from, to ); } +void Shell::slotFitWindowToPage(const QSize& pageViewSize, const QSize& pageSize ) +{ + const int xOffset = pageViewSize.width() - pageSize.width(); + const int yOffset = pageViewSize.height() - pageSize.height(); + showNormal(); + resize( width() - xOffset, height() - yOffset); + moveSplitter(pageSize.width()); +} + /* kate: replace-tabs on; indent-width 4; */ diff --git a/shell/shell.h b/shell/shell.h index 3eaed1d87..fea80acfb 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -121,6 +121,11 @@ private slots: void testTabDrop( const QDragMoveEvent* event, bool& accept ); void handleTabDrop( QDropEvent* event ); void moveTabData( int from, int to ); + + void slotFitWindowToPage( const QSize& pageViewSize, const QSize& pageSize ); + +signals: + void moveSplitter(int sideWidgetSize); private: void setupAccel(); diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 1631d9327..49d6f8a13 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -215,6 +215,7 @@ public: KAction * aSpeakStop; KActionCollection * actionCollection; QActionGroup * mouseModeActionGroup; + KAction * aFitWindowToPage; int setting_viewCols; @@ -491,6 +492,12 @@ void PageView::setupViewerActions( KActionCollection * ac ) ac->addAction("view_auto_fit", d->aZoomAutoFit ); connect( d->aZoomAutoFit, SIGNAL(toggled(bool)), SLOT(slotAutoFitToggled(bool)) ); + d->aFitWindowToPage = new KAction(KIcon( "zoom-fit-width" ), i18n("Fit Wi&ndow to Page"), this); + d->aFitWindowToPage->setEnabled( Okular::Settings::viewMode() == (int)Okular::Settings::EnumViewMode::Single ); + d->aFitWindowToPage->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_J) ); + ac->addAction( "fit_window_to_page", d->aFitWindowToPage ); + connect( d->aFitWindowToPage, SIGNAL(triggered()), this, SLOT(slotFitWindowToPage()) ); + // View-Layout actions d->aViewMode = new KActionMenu( KIcon( "view-split-left-right" ), i18n( "&View Mode" ), this ); d->aViewMode->setDelayed( false ); @@ -1077,6 +1084,8 @@ void PageView::updateActionState( bool haspages, bool documentChanged, bool hasf } if (d->aMouseMagnifier) d->aMouseMagnifier->setEnabled(d->document->supportsTiles()); + if ( d->aFitWindowToPage ) + d->aFitWindowToPage->setEnabled( haspages && !Okular::Settings::viewContinuous() ); } bool PageView::areSourceLocationsShownGraphically() const @@ -4012,8 +4021,15 @@ void PageView::toggleFormWidgets( bool on ) void PageView::resizeContentArea( const QSize & newSize ) { const QSize vs = viewport()->size(); - horizontalScrollBar()->setRange( 0, newSize.width() - vs.width() ); - verticalScrollBar()->setRange( 0, newSize.height() - vs.height() ); + int hRange = newSize.width() - vs.width(); + int vRange = newSize.height() - vs.height(); + if ( horizontalScrollBar()->isVisible() && hRange == verticalScrollBar()->width() && verticalScrollBar()->isVisible() && vRange == horizontalScrollBar()->height() && Okular::Settings::showScrollBars() ) + { + hRange = 0; + vRange = 0; + } + horizontalScrollBar()->setRange( 0, hRange ); + verticalScrollBar()->setRange( 0, vRange ); updatePageStep(); } @@ -4118,6 +4134,9 @@ void PageView::slotRelayoutPages() const bool centerLastPage = centerFirstPage && pageCount % 2 == 0; const bool continuousView = Okular::Settings::viewContinuous(); const int nCols = overrideCentering ? 1 : viewColumns(); + const bool singlePageViewMode = Okular::Settings::viewMode() == Okular::Settings::EnumViewMode::Single; + + d->aFitWindowToPage->setEnabled( !continuousView && singlePageViewMode ); // set all items geometry and resize contents. handle 'continuous' and 'single' modes separately @@ -5062,6 +5081,26 @@ void PageView::slotToggleChangeColors() viewport()->update(); } +void PageView::slotFitWindowToPage() +{ + PageViewItem currentPageItem = NULL; + QSize viewportSize = viewport()->size(); + foreach ( const PageViewItem * pageItem, d->items ) + { + if ( pageItem->isVisible() ) + { + currentPageItem = *pageItem; + break; + } + } + const QSize pageSize = QSize( currentPageItem.uncroppedWidth() + kcolWidthMargin, currentPageItem.uncroppedHeight() + krowHeightMargin ); + if ( verticalScrollBar()->isVisible() ) + viewportSize.setWidth( viewportSize.width() + verticalScrollBar()->width() ); + if ( horizontalScrollBar()->isVisible() ) + viewportSize.setHeight( viewportSize.height() + horizontalScrollBar()->height() ); + emit fitWindowToPage( viewportSize, pageSize ); +} + //END private SLOTS #include "pageview.moc" diff --git a/ui/pageview.h b/ui/pageview.h index a8adb2c13..e65b57500 100644 --- a/ui/pageview.h +++ b/ui/pageview.h @@ -124,6 +124,7 @@ Q_OBJECT void mouseBackButtonClick(); void mouseForwardButtonClick(); void escPressed(); + void fitWindowToPage( const QSize& pageViewPortSize, const QSize& pageSize ); protected: void resizeEvent( QResizeEvent* ); @@ -249,6 +250,7 @@ Q_OBJECT void slotProcessMovieAction( const Okular::MovieAction *action ); void slotProcessRenditionAction( const Okular::RenditionAction *action ); void slotToggleChangeColors(); + void slotFitWindowToPage(); }; #endif diff --git a/ui/sidebar.cpp b/ui/sidebar.cpp index 0c722a9d9..9e51a1b89 100644 --- a/ui/sidebar.cpp +++ b/ui/sidebar.cpp @@ -644,6 +644,15 @@ bool Sidebar::isCollapsed() const return d->sideContainer->isHidden(); } +void Sidebar::moveSplitter(int sideWidgetSize) +{ + QList splitterSizeList = d->splitter->sizes(); + const int total = splitterSizeList.at( 0 ) + splitterSizeList.at( 1 ); + splitterSizeList.replace( 0, total - sideWidgetSize ); + splitterSizeList.replace( 1, sideWidgetSize ); + d->splitter->setSizes( splitterSizeList ); +} + void Sidebar::itemClicked( QListWidgetItem *item ) { itemClicked( item, UncollapseIfCollapsed ); diff --git a/ui/sidebar.h b/ui/sidebar.h index cf5dfc6ce..263016678 100644 --- a/ui/sidebar.h +++ b/ui/sidebar.h @@ -42,6 +42,8 @@ class Sidebar : public QWidget void setCollapsed( bool collapsed ); bool isCollapsed() const; + void moveSplitter( int sideWidgetSize ); + signals: void urlsDropped( const KUrl::List& urls );