Abdelrazak Younes wrote: > Peter Kümmel wrote: >> While your discussion I've finished the tab implementation. :) > > I always said that, less talk, more action! > :-) > > >> Please test or comment it. >> It should be possible to port it back to 1.4 (there is also a QTabBar) > > I think it is a very good solution for 1.4 where there is only one > possible LyXView. And you could reuse the menu backend for it as the > BufferList looking and the associated LFUN is already implemented there. > This would mean a bit less code. Otherwise the code looks very clean to > my eyes.
If it's OK for JMarc. > For 1.5, while I agree that your patch is a very good first step I'd > prefer that we think a bit more about what we really want. Yes at least as starting point. > > Abdel. > > New in this patch: - tabs also handle the selection via the View menu - tabs are only showed when there is more than one document Peter
Index: frontends/LyXView.h =================================================================== --- frontends/LyXView.h (revision 15548) +++ frontends/LyXView.h (working copy) @@ -153,6 +153,9 @@ /// updates the title of the window void updateWindowTitle(); + /// updates the tab view + virtual void updateTab() = 0; + /// reset autosave timer void resetAutosaveTimer(); Index: frontends/qt4/GuiView.h =================================================================== --- frontends/qt4/GuiView.h (revision 15548) +++ frontends/qt4/GuiView.h (working copy) @@ -26,7 +26,7 @@ #include <QCloseEvent> class QToolBar; - +class WidgetWithTabBar; //class FuncRequest; //class string; @@ -70,6 +70,8 @@ virtual void clearMessage(); virtual bool hasFocus() const; + virtual void updateTab(); + /// show - display the top-level window void show(); @@ -79,6 +81,7 @@ /// menu item has been selected void activated(FuncRequest const &); + void initTab(QWidget* workArea); Q_SIGNALS: void closing(int); @@ -90,6 +93,8 @@ /// populate a toplevel menu and all its children on demand void updateMenu(QAction *); + void currentTabChanged (int index); + protected: /// make sure we quit cleanly virtual void closeEvent(QCloseEvent * e); @@ -120,6 +125,9 @@ void updateFloatingGeometry(); /// QRect floatingGeometry_; + + struct GuiViewPrivate; + GuiViewPrivate& d; }; } // namespace frontend Index: frontends/qt4/GuiImplementation.C =================================================================== --- frontends/qt4/GuiImplementation.C (revision 15548) +++ frontends/qt4/GuiImplementation.C (working copy) @@ -136,7 +136,7 @@ work_areas_[id]->setBufferView(buffer_views_[id].get()); view->setWorkArea(work_areas_[id]); - view->setCentralWidget(work_areas_[id]); + view->initTab(work_areas_[id]); return id; } Index: frontends/qt4/GuiView.C =================================================================== --- frontends/qt4/GuiView.C (revision 15548) +++ frontends/qt4/GuiView.C (working copy) @@ -38,6 +38,8 @@ #include "session.h" #include "lyxfunc.h" #include "MenuBackend.h" +#include "buffer.h" +#include "bufferlist.h" #include <QAction> #include <QApplication> @@ -45,13 +47,30 @@ #include <QPixmap> #include <QStatusBar> #include <QToolBar> +#include <QTabBar> #include <boost/bind.hpp> using std::endl; using std::string; using std::vector; +using lyx::support::onlyFilename; +class WidgetWithTabBar : public QWidget +{ +public: + QTabBar* tabbar; + WidgetWithTabBar(QWidget* w) + { + tabbar = new QTabBar; + QVBoxLayout* l = new QVBoxLayout; + l->addWidget(tabbar); + l->addWidget(w); + l->setMargin(0); + setLayout(l); + } +}; + namespace lyx { using support::subst; @@ -65,9 +84,23 @@ } // namespace anon +struct GuiView::GuiViewPrivate +{ + typedef std::map<int, FuncRequest> FuncMap; + typedef std::pair<int, FuncRequest> FuncMapPair; + typedef std::map<string, QString> NameMap; + typedef std::pair<string, QString> NameMapPair; + FuncMap funcmap; + NameMap namemap; + WidgetWithTabBar* wt; + + GuiViewPrivate() + {} +}; + GuiView::GuiView(int id) - : QMainWindow(), LyXView(id), commandbuffer_(0) + : QMainWindow(), LyXView(id), commandbuffer_(0), d(*new GuiViewPrivate) { setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_QuitOnClose, true); @@ -89,6 +122,7 @@ GuiView::~GuiView() { + delete &d; } @@ -221,7 +255,124 @@ statusbar_timer_.stop(); } +void GuiView::initTab(QWidget* workarea) +{ + d.wt = new WidgetWithTabBar(workarea); + setCentralWidget(d.wt); + QObject::connect(d.wt->tabbar, SIGNAL(currentChanged(int)), + this, SLOT(currentTabChanged(int))); +} +void GuiView::updateTab() +{ + QTabBar& tb = *d.wt->tabbar; + + // update when all is done + tb.blockSignals(true); + + typedef std::vector<string> Strings; + Strings const names = theBufferList().getFileNames(); + size_t n_size = names.size(); + + Strings addtab; + // show tabs only when there is more + // than one file opened + if (n_size > 1) + { + for (size_t i = 0; i != n_size; i++) + if (d.namemap.find(names[i]) == d.namemap.end()) + addtab.push_back(names.at(i)); + } + + for(size_t i = 0; i<addtab.size(); i++) + { + QString tab_name = lyx::toqstr(onlyFilename(addtab.at(i))); + d.namemap.insert(GuiViewPrivate::NameMapPair(addtab.at(i), tab_name)); + tb.addTab(tab_name); + } + + // check if all names showed by the tabs + // are also in the current bufferlist + Strings removetab; + bool notall = true; + if (n_size < 2) + notall = false; + std::map<string, QString>::iterator tabit = d.namemap.begin(); + for (;tabit != d.namemap.end(); ++tabit) + { + bool found = false; + for (size_t i = 0; i != n_size; i++) + if (tabit->first == names.at(i) && notall) + found = true; + if (!found) + removetab.push_back(tabit->first); + } + + + // remove tabs + for(size_t i = 0; i<removetab.size(); i++) + { + if (d.namemap.find(removetab.at(i)) != d.namemap.end()) + { + tabit = d.namemap.find(removetab.at(i)); + for (int i = 0; i < tb.count(); i++) + if (tb.tabText(i) == tabit->second) + { + tb.removeTab(i); + break; + } + d.namemap.erase(tabit); + } + } + + // rebuild func map + if (removetab.size() > 0 || addtab.size() > 0) + { + d.funcmap.clear(); + tabit = d.namemap.begin(); + for (;tabit != d.namemap.end(); ++tabit) + { + QTabBar& tb = *d.wt->tabbar; + for (int i = 0; i < tb.count(); i++) + { + if (tb.tabText(i) == tabit->second) + { + FuncRequest func(LFUN_BUFFER_SWITCH, tabit->first); + d.funcmap.insert(GuiViewPrivate::FuncMapPair(i, func)); + break; + } + } + } + } + + // set current tab + if (view()->buffer()) + { + string cur_title = view()->buffer()->fileName(); + if (d.namemap.find(cur_title) != d.namemap.end()) + { + QString tabname = d.namemap.find(cur_title)->second; + for (int i = 0; i < tb.count(); i++) + if (tb.tabText(i) == tabname) + { + tb.setCurrentIndex(i); + break; + } + } + } + + tb.blockSignals(false); + d.wt->update(); +} + +void GuiView::currentTabChanged (int index) +{ + std::map<int, FuncRequest>::const_iterator it = d.funcmap.find(index); + if (it != d.funcmap.end()) + activated(it->second); +} + + void GuiView::updateStatusBar() { // let the user see the explicit message Index: frontends/LyXView.C =================================================================== --- frontends/LyXView.C (revision 15548) +++ frontends/LyXView.C (working copy) @@ -129,6 +129,7 @@ updateLayoutChoice(); updateWindowTitle(); updateStatusBar(); + updateTab(); work_area_->redraw(); } @@ -144,6 +145,7 @@ updateToolbars(); updateLayoutChoice(); updateWindowTitle(); + updateTab(); if (loaded) { connectBuffer(*work_area_->bufferView().buffer()); showErrorList("Parse");