Skip to content

Commit

Permalink
Adds an initial tab support
Browse files Browse the repository at this point in the history
Adds tab buttons. Remembers each tab state in a struct.
  • Loading branch information
drognanar committed Aug 22, 2014
1 parent 9d2ec1f commit d5bd429
Show file tree
Hide file tree
Showing 13 changed files with 350 additions and 67 deletions.
Binary file added zeal/chrome/active_chrome_tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zeal/chrome/chrome_tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zeal/chrome/chrome_tab_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zeal/chrome/overlay_chrome_tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
228 changes: 207 additions & 21 deletions zeal/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <QMessageBox>
#include <QStyleFactory>
#include <QLocalSocket>
#include <QLayout>
#include <QSettings>
#include <QTimer>
#include <QToolButton>
Expand All @@ -23,6 +24,7 @@
#include <QAbstractNetworkCache>
#include <QWebFrame>
#include <QWebHistory>
#include <QScrollBar>
#include <QShortcut>

#ifdef WIN32
Expand Down Expand Up @@ -187,6 +189,8 @@ MainWindow::MainWindow(QWidget *parent) :
#endif
treeViewClicked = false;

createTab();

connect(ui->treeView, &QTreeView::clicked, [&](const QModelIndex& index) {
treeViewClicked = true;
ui->treeView->activated(index);
Expand All @@ -209,18 +213,16 @@ MainWindow::MainWindow(QWidget *parent) :

// paint label with the icon
loadSections(docsetName, url);
ui->pageIcon->setPixmap(docsetMap);
tabBar.setTabIcon(tabBar.currentIndex(), docsetMap);
} else {
tabBar.setTabIcon(tabBar.currentIndex(), QIcon());
}
displayViewActions();
});

connect(ui->webView, &SearchableWebView::titleChanged, [&](const QString &) {
QString title = ui->webView->page()->mainFrame()->title();
ui->pageTitle->setText(title);
ui->pageTitle->repaint();
displayViewActions();
});
ui->webView->load(QUrl("qrc:///webpage/Welcome.html"));

connect(ui->webView, &SearchableWebView::linkClicked, [&](const QUrl &url) {
QMessageBox question;
Expand All @@ -234,26 +236,72 @@ MainWindow::MainWindow(QWidget *parent) :

ui->sections->hide();
ui->sections_lab->hide();
ui->sections->setModel(&sectionsList);
ui->sections->setModel(&searchState->sectionsList);
connect(docsets, &ZealDocsetsRegistry::queryCompleted, this, &MainWindow::onSearchComplete);
connect(&zealSearch, &ZealSearchModel::queryCompleted, [&]() {
treeViewClicked = true;

ui->treeView->setModel(&zealSearch);
ui->treeView->reset();
ui->treeView->setColumnHidden(1, true);
ui->treeView->setCurrentIndex(zealSearch.index(0, 0, QModelIndex()));
ui->treeView->activated(ui->treeView->currentIndex());
});
connect(ui->lineEdit, &QLineEdit::textChanged, [&](const QString& text) {
zealSearch.setQuery(text);
if (text == searchState->searchQuery) {
return;
}

searchState->searchQuery = text;
searchState->zealSearch.setQuery(text);
if(text.isEmpty()) {
ui->treeView->setModel(&zealList);
}
});

ui->backButton->setMenu(&backMenu);
ui->forwardButton->setMenu(&forwardMenu);

ui->action_NewTab->setShortcut(QKeySequence::AddTab);
connect(ui->action_NewTab, &QAction::triggered, [&]() {
saveTabState();
createTab();
});

// save the expanded items:
connect(ui->treeView, &QTreeView::expanded, [&](QModelIndex index) {
if (searchState->expansions.indexOf(index) == -1) {
searchState->expansions.append(index);
}
});

connect(ui->treeView, &QTreeView::collapsed, [&](QModelIndex index) {
searchState->expansions.removeOne(index);
});

ui->action_CloseTab->setShortcut(QKeySequence::Close);
connect(ui->action_CloseTab, &QAction::triggered, [&]() {
closeTab(-1);
});

tabBar.setTabsClosable(false);
tabBar.setExpanding(false);
tabBar.setUsesScrollButtons(true);
tabBar.setDrawBase(false);
tabBar.setStyle(QStyleFactory::create("fusion"));

connect(&tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab);
((QHBoxLayout*)ui->frame_2->layout())->insertWidget(2, &tabBar, 0, Qt::AlignBottom);

connect(&tabBar, &QTabBar::currentChanged, this, &MainWindow::goToTab);

connect(ui->openUrlButton, &QPushButton::clicked, [&]() {
QUrl url(ui->webView->page()->history()->currentItem().url());
if (url.scheme() != "qrc") {
QDesktopServices::openUrl(url);
}
});

ui->action_NextTab->setShortcut(QKeySequence::NextChild);
connect(ui->action_NextTab, &QAction::triggered, [&]() {
tabBar.setCurrentIndex((tabBar.currentIndex() + 1) % tabBar.count());
});

ui->action_PreviousTab->setShortcut(QKeySequence::PreviousChild);
connect(ui->action_PreviousTab, &QAction::triggered, [&]() {
tabBar.setCurrentIndex((tabBar.currentIndex() - 1 + tabBar.count()) % tabBar.count());
});
}

MainWindow::~MainWindow()
Expand All @@ -279,9 +327,147 @@ void MainWindow::openDocset(const QModelIndex &index)
}
}

void MainWindow::queryCompleted()
{
treeViewClicked = true;

ui->treeView->setModel(&searchState->zealSearch);
ui->treeView->reset();
ui->treeView->setColumnHidden(1, true);
ui->treeView->setCurrentIndex(searchState->zealSearch.index(0, 0, QModelIndex()));
ui->treeView->activated(ui->treeView->currentIndex());
}

void MainWindow::goToTab(int index)
{
saveTabState();
searchState = tabs.at(index);
reloadTabState();
}

void MainWindow::closeTab(int index = -1)
{
if (index == -1) {
index = tabBar.currentIndex();
}

// TODO: proper deletion here
tabs.removeAt(index);

if (tabs.count() == 0) {
createTab();
}
tabBar.removeTab(index);
}

void MainWindow::createTab()
{
SearchState *newTab = new SearchState();
connect(&newTab->zealSearch, &ZealSearchModel::queryCompleted, this, &MainWindow::queryCompleted);
connect(&newTab->sectionsList, &ZealSearchModel::queryCompleted, [=]() {
int resultCount = newTab->sectionsList.rowCount(QModelIndex());
ui->sections->setVisible(resultCount > 1);
ui->sections_lab->setVisible(resultCount > 1);
});

ui->lineEdit->setText("");

newTab->page = new QWebPage(ui->webView);

ui->treeView->setModel(NULL);
ui->treeView->setModel(&zealList);
ui->treeView->setColumnHidden(1, true);

tabs.append(newTab);
searchState = newTab;

tabBar.addTab("title");
tabBar.setCurrentIndex(tabs.size() - 1);

reloadTabState();
newTab->page->mainFrame()->load(QUrl("qrc:///webpage/Welcome.html"));
}

void MainWindow::displayTabs()
{
ui->menu_Tabs->clear();
ui->menu_Tabs->addAction(ui->action_NewTab);
ui->menu_Tabs->addAction(ui->action_CloseTab);
ui->menu_Tabs->addSeparator();
ui->menu_Tabs->addAction(ui->action_NextTab);
ui->menu_Tabs->addAction(ui->action_PreviousTab);
ui->menu_Tabs->addSeparator();

ui->action_NextTab->setEnabled(tabBar.count() > 1);
ui->action_PreviousTab->setEnabled(tabBar.count() > 1);

for (int i = 0; i < tabs.count(); i++) {
SearchState *state = tabs.at(i);
QString title = state->page->history()->currentItem().title();
QAction *action = ui->menu_Tabs->addAction(title);
action->setCheckable(true);
action->setChecked(i == tabBar.currentIndex());
if (title.length() >= 20) {
title.truncate(17);
title += "...";
}
tabBar.setTabText(i, title);
connect(action, &QAction::triggered, [=]() {
tabBar.setCurrentIndex(i);
});
}
}

void MainWindow::reloadTabState()
{
ui->lineEdit->setText(searchState->searchQuery);
ui->sections->setModel(&searchState->sectionsList);
ui->treeView->reset();

if (!searchState->searchQuery.isEmpty()) {
ui->treeView->setModel(&searchState->zealSearch);
} else {
ui->treeView->setModel(&zealList);
ui->treeView->setColumnHidden(1, true);
}

// Bring back the selections and expansions.
for (QModelIndex selection: searchState->selections) {
ui->treeView->selectionModel()->select(selection, QItemSelectionModel::Select);
}
for (QModelIndex expandedIndex: searchState->expansions) {
ui->treeView->expand(expandedIndex);
}

ui->webView->setPage(searchState->page);

int resultCount = searchState->sectionsList.rowCount(QModelIndex());
ui->sections->setVisible(resultCount > 1);
ui->sections_lab->setVisible(resultCount > 1);

// scroll after the object gets loaded
QTimer::singleShot(100, this, SLOT(scrollSearch()));

displayViewActions();
}

void MainWindow::scrollSearch()
{
ui->treeView->verticalScrollBar()->setValue(searchState->scrollPosition);
ui->sections->verticalScrollBar()->setValue(searchState->sectionsScroll);
}

void MainWindow::saveTabState()
{
searchState->searchQuery = ui->lineEdit->text();
searchState->selections = ui->treeView->selectionModel()->selectedIndexes();
searchState->scrollPosition = ui->treeView->verticalScrollBar()->value();
searchState->sectionsScroll = ui->sections->verticalScrollBar()->value();
}

void MainWindow::onSearchComplete()
{
zealSearch.onQueryCompleted(docsets->getQueryResults());
searchState->zealSearch.onQueryCompleted(docsets->getQueryResults());
}

void MainWindow::loadSections(const QString docsetName, const QUrl &url)
Expand All @@ -292,9 +478,7 @@ void MainWindow::loadSections(const QString docsetName, const QUrl &url)
QString path = url.path().mid(dirPosition + dir.size() + 1);
// resolve the url to use the docset related path.
QList<ZealSearchResult> results = docsets->getRelatedLinks(docsetName, path);
sectionsList.onQueryCompleted(results);
ui->sections->setVisible(results.size() > 1);
ui->sections_lab->setVisible(results.size() > 1);
searchState->sectionsList.onQueryCompleted(results);
}

// Sets up the search box autocompletions.
Expand Down Expand Up @@ -335,6 +519,8 @@ void MainWindow::displayViewActions() {
for (QWebHistoryItem item: history->forwardItems(10)) {
forwardMenu.addAction(addHistoryAction(history, item));
}

displayTabs();
}

void MainWindow::back() {
Expand Down Expand Up @@ -442,7 +628,7 @@ void MainWindow::bringToFront(bool withHack)
void MainWindow::bringToFrontAndSearch(const QString query)
{
bringToFront(true);
zealSearch.setQuery(query);
searchState->zealSearch.setQuery(query);
ui->lineEdit->setText(query);
ui->treeView->setFocus();
ui->treeView->activated(ui->treeView->currentIndex());
Expand Down
40 changes: 38 additions & 2 deletions zeal/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QSystemTrayIcon>
#include <QCloseEvent>
#include <QWebHistory>
#include <QModelIndex>
#include "zeallistmodel.h"
#include "zealsearchmodel.h"
#include "zealnativeeventfilter.h"
Expand All @@ -27,6 +28,28 @@ class MainWindow;

extern const QString serverName;

// Represents per tab search state.
// needs to contain [search input, search model, section model, url]
typedef struct SearchState
{
public:
QWebPage *page;
// model representing sections
ZealSearchModel sectionsList;
// model representing searched for items
ZealSearchModel zealSearch;
// query being searched for
QString searchQuery;

// list of selected indices
QModelIndexList selections;
// list of expanded indices
QModelIndexList expansions;

int scrollPosition;
int sectionsScroll;
} SearchState;

class MainWindow : public QMainWindow
{
Q_OBJECT
Expand All @@ -42,13 +65,20 @@ class MainWindow : public QMainWindow
void displayViewActions();
void loadSections(const QString docsetName, const QUrl &url);
void setupSearchBoxCompletions();
void createTab();
void reloadTabState();
void displayTabs();
void updateTreeView(QString text);
QAction *addHistoryAction(QWebHistory *history, QWebHistoryItem item);

QList<SearchState*> tabs;

SearchState *searchState;

Ui::MainWindow *ui;
QIcon icon;
ZealListModel zealList;
ZealSearchModel zealSearch;
ZealSearchModel sectionsList;

QLocalServer *localServer;
QMenu backMenu;
QMenu forwardMenu;
Expand All @@ -58,6 +88,7 @@ class MainWindow : public QMainWindow
void setHotKey(const QKeySequence& hotKey);
QKeySequence hotKey;
QSettings settings;
QTabBar tabBar;
ZealNativeEventFilter nativeFilter;
ZealSettingsDialog settingsDialog;
QSystemTrayIcon *trayIcon;
Expand All @@ -74,6 +105,11 @@ private slots:
void forward();
void onSearchComplete();
void openDocset(const QModelIndex& index);
void queryCompleted();
void scrollSearch();
void saveTabState();
void goToTab(int index);
void closeTab(int index);
protected:
void closeEvent(QCloseEvent *event) {
settings.setValue("geometry", saveGeometry());
Expand Down
Loading

0 comments on commit d5bd429

Please sign in to comment.