diff --git a/config.cc b/config.cc index 32f4b86c..adf58f7a 100644 --- a/config.cc +++ b/config.cc @@ -85,6 +85,7 @@ Preferences::Preferences(): newTabsOpenAfterCurrentOne( false ), newTabsOpenInBackground( true ), hideSingleTab( false ), + mruTabOrder ( false ), hideMenubar( false ), enableTrayIcon( true ), startToTray( false ), @@ -570,6 +571,7 @@ Class load() throw( exError ) c.preferences.newTabsOpenAfterCurrentOne = ( preferences.namedItem( "newTabsOpenAfterCurrentOne" ).toElement().text() == "1" ); c.preferences.newTabsOpenInBackground = ( preferences.namedItem( "newTabsOpenInBackground" ).toElement().text() == "1" ); c.preferences.hideSingleTab = ( preferences.namedItem( "hideSingleTab" ).toElement().text() == "1" ); + c.preferences.mruTabOrder = ( preferences.namedItem( "mruTabOrder" ).toElement().text() == "1" ); c.preferences.hideMenubar = ( preferences.namedItem( "hideMenubar" ).toElement().text() == "1" ); c.preferences.enableTrayIcon = ( preferences.namedItem( "enableTrayIcon" ).toElement().text() == "1" ); c.preferences.startToTray = ( preferences.namedItem( "startToTray" ).toElement().text() == "1" ); @@ -1038,6 +1040,10 @@ void save( Class const & c ) throw( exError ) opt.appendChild( dd.createTextNode( c.preferences.hideSingleTab ? "1":"0" ) ); preferences.appendChild( opt ); + opt = dd.createElement( "mruTabOrder" ); + opt.appendChild( dd.createTextNode( c.preferences.mruTabOrder ? "1":"0" ) ); + preferences.appendChild( opt ); + opt = dd.createElement( "hideMenubar" ); opt.appendChild( dd.createTextNode( c.preferences.hideMenubar ? "1":"0" ) ); preferences.appendChild( opt ); diff --git a/config.hh b/config.hh index 5420e48f..4ede9c2a 100644 --- a/config.hh +++ b/config.hh @@ -140,6 +140,7 @@ struct Preferences bool newTabsOpenAfterCurrentOne; bool newTabsOpenInBackground; bool hideSingleTab; + bool mruTabOrder; bool hideMenubar; bool enableTrayIcon; bool startToTray; diff --git a/goldendict.pro b/goldendict.pro index 9b070358..e47416b5 100644 --- a/goldendict.pro +++ b/goldendict.pro @@ -189,7 +189,8 @@ HEADERS += folding.hh \ dprintf.hh \ mainstatusbar.hh \ gdappstyle.hh \ - ufile.hh + ufile.hh \ + mruqmenu.hh FORMS += groups.ui \ dictgroupwidget.ui \ mainwindow.ui \ @@ -277,7 +278,8 @@ SOURCES += folding.cc \ maintabwidget.cc \ mainstatusbar.cc \ gdappstyle.cc \ - ufile.cc + ufile.cc \ + mruqmenu.cc win32 { SOURCES += mouseover_win32/ThTypes.c \ wordbyauto.cc \ diff --git a/mainwindow.cc b/mainwindow.cc index 458d64f6..70ecf7bc 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -6,10 +6,12 @@ #include "loaddictionaries.hh" #include "preferences.hh" #include "about.hh" +#include "mruqmenu.hh" #include #include #include #include +#include #include #include #include @@ -203,6 +205,9 @@ MainWindow::MainWindow( Config::Class & cfg_ ): addTabAction.setShortcut( QKeySequence( "Ctrl+T" ) ); // Tab management + tabListMenu = new MRUQMenu(tr("Opened tabs"), ui.tabWidget); + + connect (tabListMenu, SIGNAL(ctrlReleased()), this, SLOT(ctrlReleased())); connect( &addTabAction, SIGNAL( triggered() ), this, SLOT( addNewTab() ) ); @@ -423,6 +428,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ): ui.wordList->viewport()->installEventFilter( this ); ui.dictsList->installEventFilter( this ); ui.dictsList->viewport()->installEventFilter( this ); + //tabWidget doesn't propagate Ctrl+Tab to the parent widget unless event filter is installed + ui.tabWidget->installEventFilter( this ); if ( cfg.mainWindowGeometry.size() ) restoreGeometry( cfg.mainWindowGeometry ); @@ -499,6 +506,12 @@ MainWindow::MainWindow( Config::Class & cfg_ ): updateStatusLine(); } +void MainWindow::ctrlTabPressed() +{ + emit fillWindowsMenu(); + tabListButton->click(); +} + void MainWindow::mousePressEvent( QMouseEvent *event) { @@ -846,7 +859,6 @@ vector< sptr< Dictionary::Class > > const & MainWindow::getActiveDicts() void MainWindow::createTabList() { - tabListMenu = new QMenu(tr("Opened tabs"), ui.tabWidget); tabListMenu->setIcon(QIcon(":/icons/windows-list.png")); connect(tabListMenu, SIGNAL(aboutToShow()), this, SLOT(fillWindowsMenu())); connect(tabListMenu, SIGNAL(triggered(QAction*)), this, SLOT(switchToWindow(QAction*))); @@ -865,18 +877,43 @@ void MainWindow::fillWindowsMenu() { tabListMenu->clear(); - for (int i = 0; i < ui.tabWidget->count(); i++) + if(cfg.preferences.mruTabOrder) { - QAction *act = tabListMenu->addAction( ui.tabWidget->tabIcon( i ), - ui.tabWidget->tabText( i ) ); - act->setData( i ); - if (ui.tabWidget->currentIndex() == i) + for (int i = 0; i < mruList.count(); i++) { - QFont f( act->font() ); - f.setBold( true ); - act->setFont( f ); + QAction *act = tabListMenu->addAction(ui.tabWidget->tabIcon(ui.tabWidget->indexOf(mruList.at(i))), ui.tabWidget->tabText(ui.tabWidget->indexOf(mruList.at(i)))); + + //remember the index of the Tab to be later used in ctrlReleased() + act->setData(ui.tabWidget->indexOf(mruList.at(i))); + + if (ui.tabWidget->currentIndex() == ui.tabWidget->indexOf(mruList.at(i))) + { + QFont f( act->font() ); + f.setBold( true ); + act->setFont( f ); + } + } + if (tabListMenu->actions().size() > 1) + { + tabListMenu->setActiveAction(tabListMenu->actions().at(1)); } } + else + { + for (int i = 0; i < ui.tabWidget->count(); i++) + { + QAction *act = tabListMenu->addAction( ui.tabWidget->tabIcon( i ), + ui.tabWidget->tabText( i ) ); + act->setData( i ); + if (ui.tabWidget->currentIndex() == i) + { + QFont f( act->font() ); + f.setBold( true ); + act->setFont( f ); + } + } + } + return; } void MainWindow::switchToWindow(QAction *act) @@ -933,6 +970,7 @@ ArticleView * MainWindow::createNewTab( bool switchToIt, escaped.replace( "&", "&&" ); ui.tabWidget->insertTab( index, view, escaped ); + mruList.append(dynamic_cast(view)); if ( switchToIt ) ui.tabWidget->setCurrentIndex( index ); @@ -950,10 +988,29 @@ void MainWindow::tabCloseRequested( int x ) QWidget * w = ui.tabWidget->widget( x ); + if (cfg.preferences.mruTabOrder) + { + //removeTab activates next tab and emits currentChannged SIGNAL + //This is not what we want for MRU, so disable the signal for a moment + + disconnect( ui.tabWidget, SIGNAL( currentChanged( int ) ), + this, SLOT( tabSwitched( int ) ) ); + } + ui.tabWidget->removeTab( x ); + if (cfg.preferences.mruTabOrder) + { + connect( ui.tabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( tabSwitched( int ) ) ); + } + + mruList.removeOne(w); + delete w; + //activate a tab in accordance with MRU + ui.tabWidget->setCurrentWidget(mruList.at(0)); + // if everything is closed, add new tab if ( ui.tabWidget->count() == 0 ) addNewTab(); @@ -1008,6 +1065,16 @@ void MainWindow::switchToPrevTab() ui.tabWidget->setCurrentIndex( ui.tabWidget->currentIndex() - 1 ); } +//emitted by tabListMenu when user releases Ctrl +void MainWindow::ctrlReleased() +{ + if (tabListMenu->actions().size() > 1) + { + ui.tabWidget->setCurrentIndex(tabListMenu->activeAction()->data().toInt()); + } + tabListMenu->hide(); +} + void MainWindow::backClicked() { DPRINTF( "Back\n" ); @@ -1072,6 +1139,10 @@ void MainWindow::tabSwitched( int ) updatePronounceAvailability(); updateFoundInDictsList(); updateWindowTitle(); + if (mruList.size() > 1) + { + mruList.move(mruList.indexOf(ui.tabWidget->widget(ui.tabWidget->currentIndex())),0); + } } void MainWindow::tabMenuRequested(QPoint pos) @@ -1519,7 +1590,21 @@ bool MainWindow::eventFilter( QObject * obj, QEvent * ev ) return handleBackForwardMouseButtons( event ); } - if ( obj == ui.translateLine ) + if (ev->type() == QEvent::KeyPress) + { + QKeyEvent *keyevent = static_cast(ev); + if (keyevent->modifiers() == Qt::ControlModifier && keyevent->key() == Qt::Key_Tab) + { + if (cfg.preferences.mruTabOrder) + { + ctrlTabPressed(); + return true; + } + return false; + } + } + + if ( obj == ui.translateLine ) { if ( ev->type() == QEvent::KeyPress ) { @@ -1621,7 +1706,6 @@ bool MainWindow::eventFilter( QObject * obj, QEvent * ev ) } } } - else return QMainWindow::eventFilter( obj, ev ); return false; diff --git a/mainwindow.hh b/mainwindow.hh index 30941997..b17f158c 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -23,6 +23,7 @@ #include "history.hh" #include "hotkeywrapper.hh" #include "mainstatusbar.hh" +#include "mruqmenu.hh" #ifdef Q_WS_X11 #include @@ -80,7 +81,10 @@ private: QAction * zoomIn, * zoomOut, * zoomBase; QAction * wordsZoomIn, * wordsZoomOut, * wordsZoomBase; QMenu trayIconMenu; - QMenu *tabListMenu, *tabMenu; + QMenu *tabMenu; + MRUQMenu *tabListMenu; + //List that contains indexes of tabs arranged in a most-recently-used order + QList mruList; QToolButton addTab, *tabListButton; Config::Class & cfg; Config::Events configEvents; @@ -165,6 +169,7 @@ private: bool handleBackForwardMouseButtons(QMouseEvent *ev); ArticleView * getCurrentArticleView(); + void ctrlTabPressed(); private slots: @@ -194,6 +199,7 @@ private slots: void closeRestTabs(); void switchToNextTab(); void switchToPrevTab(); + void ctrlReleased(); // Handling of active tab list void createTabList(); diff --git a/mruqmenu.cc b/mruqmenu.cc new file mode 100644 index 00000000..95efee08 --- /dev/null +++ b/mruqmenu.cc @@ -0,0 +1,20 @@ +#include "mruqmenu.hh" +#include + +MRUQMenu::MRUQMenu(const QString title, QWidget *parent): + QMenu(title,parent) +{ + installEventFilter(this); +} + +bool MRUQMenu::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::KeyRelease){ + QKeyEvent *keyevent = static_cast(event); + if (keyevent->key() == Qt::Key_Control){ + emit ctrlReleased(); + return true; + } + } + return false; +} diff --git a/mruqmenu.hh b/mruqmenu.hh new file mode 100644 index 00000000..c2cf6fff --- /dev/null +++ b/mruqmenu.hh @@ -0,0 +1,25 @@ +#ifndef MRUQMENU_HH +#define MRUQMENU_HH + +#include +#include + +//The only difference between this class and QMenu is that this class emits +//a signal when Ctrl button is released +class MRUQMenu: public QMenu +{ + Q_OBJECT + +public: + MRUQMenu(const QString title, QWidget *parent = 0); + +private: + bool eventFilter (QObject*, QEvent*); + + signals: + void ctrlReleased(); +}; + + + +#endif // MRUQMENU_HH diff --git a/preferences.cc b/preferences.cc index d7172833..9b0a34c3 100644 --- a/preferences.cc +++ b/preferences.cc @@ -89,6 +89,7 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ): ui.newTabsOpenAfterCurrentOne->setChecked( p.newTabsOpenAfterCurrentOne ); ui.newTabsOpenInBackground->setChecked( p.newTabsOpenInBackground ); ui.hideSingleTab->setChecked( p.hideSingleTab ); + ui.mruTabOrder->setChecked( p.mruTabOrder ); ui.enableTrayIcon->setChecked( p.enableTrayIcon ); ui.startToTray->setChecked( p.startToTray ); ui.closeToTray->setChecked( p.closeToTray ); @@ -203,6 +204,7 @@ Config::Preferences Preferences::getPreferences() p.newTabsOpenAfterCurrentOne = ui.newTabsOpenAfterCurrentOne->isChecked(); p.newTabsOpenInBackground = ui.newTabsOpenInBackground->isChecked(); p.hideSingleTab = ui.hideSingleTab->isChecked(); + p.mruTabOrder = ui.mruTabOrder->isChecked(); p.enableTrayIcon = ui.enableTrayIcon->isChecked(); p.startToTray = ui.startToTray->isChecked(); p.closeToTray = ui.closeToTray->isChecked(); diff --git a/preferences.ui b/preferences.ui index f6d5d26b..cc72bfce 100644 --- a/preferences.ui +++ b/preferences.ui @@ -7,7 +7,7 @@ 0 0 572 - 357 + 376 @@ -94,6 +94,13 @@ be the last ones. + + + + Ctrl-Tab navigates tabs in MRU order + + +