ui: Added history of last active symbols to UI and menu (issue 151)

* holding down back or forward button shows list of current back-forward stack
* added narrow button between back and forward to show the list
* added History menu
* moved back and forward actions to History menu
* show chronological list of recently active symbols in History menu

bug id = 151

fortune cookie message = Dein Geschäft wird gut laufen und expandieren.
This commit is contained in:
Eberhard Graether
2017-05-09 17:14:43 +02:00
parent bb8c2ae5a9
commit f4caacacf2
30 changed files with 668 additions and 65 deletions
+141
View File
@@ -0,0 +1,141 @@
#include "QtHistoryList.h"
#include <QLabel>
#include <QBoxLayout>
#include "utility/messaging/type/MessageToUndoRedoPosition.h"
#include "utility/ResourcePaths.h"
#include "utility/utilityString.h"
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
#include "component/view/GraphViewStyle.h"
#include "data/search/SearchMatch.h"
#include "settings/ColorScheme.h"
QtHistoryItem::QtHistoryItem(const SearchMatch& match, size_t index, bool isCurrent)
: index(index)
{
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
std::string name = utility::elide(match.nodeType == Node::NODE_FILE ? match.text : match.name, utility::ELIDE_RIGHT, 100);
m_name = new QLabel(name.c_str(), this);
m_name->setAttribute(Qt::WA_MacShowFocusRect, 0);
m_name->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_name->setObjectName(isCurrent ? "history_item_current" : "history_item");
m_name->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
layout->addWidget(m_name);
setLayout(layout);
ColorScheme* scheme = ColorScheme::getInstance().get();
std::string searchTextColor = scheme->getColor("search/popup/text");
std::string color;
std::string hoverColor;
std::string textColor = searchTextColor;
std::string textHoverColor = searchTextColor;
if (match.searchType == SearchMatch::SEARCH_TOKEN)
{
color = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), false).fill;
hoverColor = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), true).fill;
textColor = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), false).text;
textHoverColor = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), true).text;
}
else
{
std::string typeName = match.getSearchTypeName();
color = scheme->getSearchTypeColor(typeName, "fill");
hoverColor = scheme->getSearchTypeColor(typeName, "fill", "hover");
textColor = scheme->getSearchTypeColor(typeName, "text");
textHoverColor = scheme->getSearchTypeColor(typeName, "text", "hover");;
}
std::stringstream css;
css << "QLabel { background-color:" << color << "; color:" << textColor << ";} ";
if (!isCurrent)
{
css << "QLabel:hover { background-color:" << hoverColor << "; color:" << textHoverColor << ";} ";
}
m_name->setStyleSheet(css.str().c_str());
if (isCurrent)
{
QSize size = getSizeHint();
QtDeviceScaledPixmap pixmap(QString::fromStdString(ResourcePaths::getGuiPath().str() + "history_list/images/arrow.png"));
pixmap.scaleToHeight(size.height() / 3);
QLabel* arrow = new QLabel(this);
arrow->setPixmap(utility::colorizePixmap(pixmap.pixmap(), QColor(scheme->getColor("search/popup/text").c_str())));
arrow->setGeometry(size.height() / 3, size.height() / 3, size.height() / 3, size.height() / 3);
arrow->show();
}
}
QSize QtHistoryItem::getSizeHint() const
{
return QSize(m_name->fontMetrics().width(m_name->text()) + 40, m_name->fontMetrics().height() + 8);
}
QtHistoryList::QtHistoryList(const std::vector<SearchMatch>& history, size_t currentIndex)
: m_currentIndex(currentIndex)
{
setObjectName("history_list");
setWindowFlags(Qt::Popup);
for (size_t i = 0; i < history.size(); i++)
{
QListWidgetItem *item = new QListWidgetItem(this);
QtHistoryItem* line = new QtHistoryItem(history[i], i, i == currentIndex);
item->setSizeHint(line->getSizeHint());
setItemWidget(item, line);
}
setStyleSheet(utility::getStyleSheet(ResourcePaths::getGuiPath().concat(FilePath("history_list/history_list.css"))).c_str());
connect(this, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(onItemClicked(QListWidgetItem*)));
}
void QtHistoryList::showPopup(QPoint pos)
{
QSize size(50, 1);
for (int i = 0; i < count(); i++)
{
QtHistoryItem* it = dynamic_cast<QtHistoryItem*>(itemWidget(item(i)));
QSize itemSize = it->getSizeHint();
if (itemSize.width() > size.width())
{
size.setWidth(itemSize.width());
}
size.setHeight(size.height() + item(i)->sizeHint().height());
}
setGeometry(pos.x(), pos.y(), size.width(), size.height());
show();
}
void QtHistoryList::onItemClicked(QListWidgetItem *item)
{
QtHistoryItem* historyItem = dynamic_cast<QtHistoryItem*>(itemWidget(item));
if (historyItem)
{
if (historyItem->index != m_currentIndex)
{
MessageToUndoRedoPosition(historyItem->index).dispatch();
}
close();
}
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef QT_HISTORY_LIST_H
#define QT_HISTORY_LIST_H
#include <QListWidget>
class QLabel;
struct SearchMatch;
class QtHistoryItem
: public QWidget
{
Q_OBJECT
public:
QtHistoryItem(const SearchMatch& match, size_t index, bool isCurrent);
QSize getSizeHint() const;
size_t index;
private:
QLabel* m_name;
};
class QtHistoryList
: public QListWidget
{
Q_OBJECT
public:
QtHistoryList(const std::vector<SearchMatch>& history, size_t currentIndex);
void showPopup(QPoint pos);
private slots:
void onItemClicked(QListWidgetItem *item);
private:
size_t m_currentIndex;
};
#endif // QT_HISTORY_LIST_H
@@ -724,7 +724,6 @@ void QtSmartSearchBox::updateElements()
if (match.searchType == SearchMatch::SEARCH_TOKEN)
{
element->setObjectName(QString::fromStdString("search_element_" + match.getNodeTypeAsUnderscoredString()));
color = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), false).fill;
hoverColor = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), true).fill;
textColor = GraphViewStyle::getNodeColor(Node::getUnderscoredTypeString(match.nodeType), false).text;
@@ -734,7 +733,6 @@ void QtSmartSearchBox::updateElements()
{
std::string typeName = match.getSearchTypeName();
element->setObjectName(QString::fromStdString("search_element_" + typeName));
color = scheme->getSearchTypeColor(typeName, "fill");
hoverColor = scheme->getSearchTypeColor(typeName, "fill", "hover");
textColor = scheme->getSearchTypeColor(typeName, "text");
+75 -11
View File
@@ -2,16 +2,19 @@
#include <QPushButton>
#include <QHBoxLayout>
#include <QTimer>
#include "utility/messaging/type/MessageUndo.h"
#include "utility/messaging/type/MessageRedo.h"
#include "utility/ResourcePaths.h"
#include "qt/element/QtHistoryList.h"
#include "qt/utility/utilityQt.h"
#include "qt/utility/QtContextMenu.h"
#include "settings/ApplicationSettings.h"
QtUndoRedo::QtUndoRedo()
: m_pressed(false)
{
setObjectName("undo_redo_bar");
@@ -21,11 +24,17 @@ QtUndoRedo::QtUndoRedo()
m_undoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_undoButton->setEnabled(false);
m_historyButton = new QPushButton(this);
m_historyButton->setObjectName("history_button");
m_historyButton->setToolTip("history");
m_historyButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_historyButton->setEnabled(false);
m_redoButton = new QPushButton(this);
m_redoButton->setObjectName("redo_button");
m_redoButton->setToolTip("forward");
m_redoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_redoButton->setEnabled(false);
m_redoButton->setEnabled(false);
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
@@ -33,47 +42,97 @@ QtUndoRedo::QtUndoRedo()
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
layout->addWidget(m_undoButton);
layout->addWidget(m_historyButton);
layout->addWidget(m_redoButton);
connect(m_undoButton, SIGNAL(clicked()), this, SLOT(undo()));
connect(m_redoButton, SIGNAL(clicked()), this, SLOT(redo()));
connect(m_undoButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
connect(m_redoButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
connect(m_historyButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
refreshStyle();
connect(m_undoButton, SIGNAL(released()), this, SLOT(undoReleased()));
connect(m_redoButton, SIGNAL(released()), this, SLOT(redoReleased()));
connect(m_historyButton, SIGNAL(released()), this, SLOT(showHistory()));
refreshStyle();
}
QtUndoRedo::~QtUndoRedo()
{
}
void QtUndoRedo::undo()
void QtUndoRedo::buttonPressed()
{
MessageUndo().dispatch();
m_pressed = true;
QTimer::singleShot(250, this, SLOT(showHistory()));
m_historyButton->setAttribute(Qt::WA_UnderMouse, false);
}
void QtUndoRedo::redo()
void QtUndoRedo::undoReleased()
{
MessageRedo().dispatch();
if (m_pressed)
{
m_pressed = false;
MessageUndo().dispatch();
}
}
void QtUndoRedo::redoReleased()
{
if (m_pressed)
{
m_pressed = false;
MessageRedo().dispatch();
}
}
void QtUndoRedo::showHistory()
{
if (m_pressed)
{
m_pressed = false;
m_undoButton->setDown(false);
m_redoButton->setDown(false);
m_historyButton->setDown(false);
m_undoButton->setAttribute(Qt::WA_UnderMouse, false);
m_redoButton->setAttribute(Qt::WA_UnderMouse, false);
m_historyButton->setAttribute(Qt::WA_UnderMouse, false);
QtHistoryList* list = new QtHistoryList(m_history, m_currentIndex);
QPoint pos = m_undoButton->mapToGlobal(m_undoButton->pos());
list->showPopup(QPoint(pos.x(), pos.y() + m_undoButton->size().height() + 5));
}
}
void QtUndoRedo::setUndoButtonEnabled(bool enabled)
{
m_undoButton->setEnabled(enabled);
m_undoButton->setEnabled(enabled);
QtContextMenu::getInstance()->enableUndo(enabled);
}
void QtUndoRedo::setRedoButtonEnabled(bool enabled)
{
m_redoButton->setEnabled(enabled);
m_redoButton->setEnabled(enabled);
QtContextMenu::getInstance()->enableRedo(enabled);
}
void QtUndoRedo::updateHistory(const std::vector<SearchMatch>& searchMatches, size_t currentIndex)
{
m_history = searchMatches;
m_currentIndex = currentIndex;
m_historyButton->setEnabled(m_history.size() > 1);
}
void QtUndoRedo::refreshStyle()
{
float height = std::max(ApplicationSettings::getInstance()->getFontSize() + 16, 30);
m_undoButton->setFixedHeight(height);
m_redoButton->setFixedHeight(height);
m_historyButton->setFixedHeight(height);
m_undoButton->setIcon(utility::createButtonIcon(
ResourcePaths::getGuiPath().str() + "undoredo_view/images/arrow_left.png",
@@ -84,4 +143,9 @@ void QtUndoRedo::refreshStyle()
ResourcePaths::getGuiPath().str() + "undoredo_view/images/arrow_right.png",
"search/button"
));
m_historyButton->setIcon(utility::createButtonIcon(
ResourcePaths::getGuiPath().str() + "undoredo_view/images/history.png",
"search/button"
));
}
+14 -2
View File
@@ -4,6 +4,7 @@
#include <string>
#include <QFrame>
#include "data/search/SearchMatch.h"
class QPushButton;
@@ -19,16 +20,27 @@ public:
void setRedoButtonEnabled(bool enabled);
void setUndoButtonEnabled(bool enabled);
void updateHistory(const std::vector<SearchMatch>& searchMatches, size_t currentIndex);
void refreshStyle();
private slots:
void undo();
void redo();
void buttonPressed();
void undoReleased();
void redoReleased();
void showHistory();
private:
QPushButton* m_undoButton;
QPushButton* m_historyButton;
QPushButton* m_redoButton;
std::vector<SearchMatch> m_history;
size_t m_currentIndex;
bool m_pressed;
};
#endif // QT_UNDO_REDO_H
+10
View File
@@ -104,6 +104,16 @@ void QtMainView::updateRecentProjectMenu()
m_updateRecentProjectMenuFunctor();
}
void QtMainView::updateHistoryMenu(const std::vector<SearchMatch>& history)
{
m_onQtThread(
[=]()
{
m_window->updateHistoryMenu(history);
}
);
}
void QtMainView::handleMessage(MessageForceEnterLicense* message)
{
m_forceLicenseScreenFunctor(message->licenseExpired);
+1
View File
@@ -49,6 +49,7 @@ public:
virtual void setTitle(const std::string& title);
virtual void activateWindow();
virtual void updateRecentProjectMenu();
virtual void updateHistoryMenu(const std::vector<SearchMatch>& history);
private:
void handleMessage(MessageForceEnterLicense* message);
+36 -29
View File
@@ -1,17 +1,13 @@
#include "qt/view/QtUndoRedoView.h"
#include "utility/ResourcePaths.h"
#include "qt/utility/utilityQt.h"
#include "qt/view/QtMainView.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "utility/ResourcePaths.h"
QtUndoRedoView::QtUndoRedoView(ViewLayout* viewLayout)
: UndoRedoView(viewLayout)
, m_refreshFunctor(std::bind(&QtUndoRedoView::doRefreshView, this))
, m_setRedoButtonEnabledFunctor(std::bind(&QtUndoRedoView::doSetRedoButtonEnabled, this, std::placeholders::_1))
, m_setUndoButtonEnabledFunctor(std::bind(&QtUndoRedoView::doSetUndoButtonEnabled, this, std::placeholders::_1))
{
m_widget = new QtUndoRedo();
setStyleSheet();
@@ -32,36 +28,47 @@ void QtUndoRedoView::initView()
void QtUndoRedoView::refreshView()
{
m_refreshFunctor();
}
void QtUndoRedoView::setStyleSheet()
{
m_widget->setStyleSheet(utility::getStyleSheet(ResourcePaths::getGuiPath().concat(FilePath("undoredo_view/undoredo_view.css"))).c_str());
}
void QtUndoRedoView::doRefreshView()
{
setStyleSheet();
m_widget->refreshStyle();
}
void QtUndoRedoView::doSetRedoButtonEnabled(bool enabled)
{
m_widget->setRedoButtonEnabled(enabled);
}
void QtUndoRedoView::doSetUndoButtonEnabled(bool enabled)
{
m_widget->setUndoButtonEnabled(enabled);
m_onQtThread(
[=]()
{
setStyleSheet();
m_widget->refreshStyle();
}
);
}
void QtUndoRedoView::setRedoButtonEnabled(bool enabled)
{
m_setRedoButtonEnabledFunctor(enabled);
m_onQtThread(
[=]()
{
m_widget->setRedoButtonEnabled(enabled);
}
);
}
void QtUndoRedoView::setUndoButtonEnabled(bool enabled)
{
m_setUndoButtonEnabledFunctor(enabled);
m_onQtThread(
[=]()
{
m_widget->setUndoButtonEnabled(enabled);
}
);
}
void QtUndoRedoView::updateHistory(const std::vector<SearchMatch>& searchMatches, size_t currentIndex)
{
m_onQtThread(
[=]()
{
m_widget->updateHistory(searchMatches, currentIndex);
}
);
}
void QtUndoRedoView::setStyleSheet()
{
m_widget->setStyleSheet(utility::getStyleSheet(
ResourcePaths::getGuiPath().concat(FilePath("undoredo_view/undoredo_view.css"))).c_str());
}
+6 -10
View File
@@ -23,18 +23,14 @@ public:
virtual void setRedoButtonEnabled(bool enabled);
virtual void setUndoButtonEnabled(bool enabled);
virtual void updateHistory(const std::vector<SearchMatch>& searchMatches, size_t currentIndex);
private:
void doRefreshView();
void doSetRedoButtonEnabled(bool enabled);
void doSetUndoButtonEnabled(bool enabled);
QtThreadedFunctor<void> m_refreshFunctor;
QtThreadedFunctor<bool> m_setRedoButtonEnabledFunctor;
QtThreadedFunctor<bool> m_setUndoButtonEnabledFunctor;
void setStyleSheet();
QtThreadedLambdaFunctor m_onQtThread;
QtUndoRedo* m_widget;
};
#endif // !QT_UNDO_REDO_VIEW_H
#endif // QT_UNDO_REDO_VIEW_H
+58 -6
View File
@@ -95,7 +95,8 @@ bool MouseReleaseFilter::eventFilter(QObject* obj, QEvent* event)
QtMainWindow::QtMainWindow()
: m_showDockWidgetTitleBars(true)
: m_historyMenu(nullptr)
, m_showDockWidgetTitleBars(true)
, m_windowStack(this)
{
setObjectName("QtMainWindow");
@@ -115,6 +116,7 @@ QtMainWindow::QtMainWindow()
setupProjectMenu();
setupEditMenu();
setupViewMenu();
setupHistoryMenu();
setupBookmarksMenu();
setupHelpMenu();
@@ -252,6 +254,12 @@ void QtMainWindow::forceEnterLicense(bool expired)
}
}
void QtMainWindow::updateHistoryMenu(const std::vector<SearchMatch>& history)
{
m_history = history;
setupHistoryMenu();
}
bool QtMainWindow::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate)
@@ -534,7 +542,7 @@ void QtMainWindow::resetWindowLayout()
void QtMainWindow::openRecentProject()
{
QAction *action = qobject_cast<QAction *>(sender());
QAction *action = qobject_cast<QAction*>(sender());
if (action)
{
MessageLoadProject(FilePath(action->data().toString().toStdString()), false).dispatch();
@@ -590,6 +598,19 @@ void QtMainWindow::showBookmarkBrowser()
MessageDisplayBookmarks().dispatch();
}
void QtMainWindow::openHistoryAction()
{
QAction* action = qobject_cast<QAction*>(sender());
if (action)
{
SearchMatch& match = m_history[action->data().toInt()];
MessageSearch msg({ match });
msg.isFromSearch = false;
msg.dispatch();
}
}
void QtMainWindow::setupProjectMenu()
{
QMenu *menu = new QMenu(tr("&Project"), this);
@@ -626,10 +647,6 @@ void QtMainWindow::setupEditMenu()
QMenu *menu = new QMenu(tr("&Edit"), this);
menuBar()->addMenu(menu);
menu->addAction(tr("Back"), this, SLOT(undo()), QKeySequence::Undo);
menu->addAction(tr("Forward"), this, SLOT(redo()), QKeySequence::Redo);
menu->addSeparator();
m_trialDisabledActions.push_back(menu->addAction(tr("&Refresh"), this, SLOT(refresh()), QKeySequence::Refresh));
if (QSysInfo::windowsVersion() != QSysInfo::WV_None)
{
@@ -689,6 +706,41 @@ void QtMainWindow::setupViewMenu()
m_viewMenu = menu;
}
void QtMainWindow::setupHistoryMenu()
{
if (!m_historyMenu)
{
m_historyMenu = new QMenu(tr("&History"), this);
menuBar()->addMenu(m_historyMenu);
}
else
{
m_historyMenu->clear();
}
m_historyMenu->addAction(tr("Back"), this, SLOT(undo()), QKeySequence::Undo);
m_historyMenu->addAction(tr("Forward"), this, SLOT(redo()), QKeySequence::Redo);
m_historyMenu->addSeparator();
QAction* title = new QAction(tr("Recently Active Symbols"));
title->setEnabled(false);
m_historyMenu->addAction(title);
for (size_t i = 0; i < m_history.size(); i++)
{
SearchMatch& match = m_history[i];
std::string name = utility::elide(match.nodeType == Node::NODE_FILE ? match.text : match.name, utility::ELIDE_RIGHT, 50);
QAction* action = new QAction();
action->setText(name.c_str());
action->setData(QVariant(int(i)));
connect(action, SIGNAL(triggered()), this, SLOT(openHistoryAction()));
m_historyMenu->addAction(action);
}
}
void QtMainWindow::setupBookmarksMenu()
{
QMenu *menu = new QMenu(tr("&Bookmarks"), this);
+10
View File
@@ -7,6 +7,7 @@
#include <QMainWindow>
#include "data/search/SearchMatch.h"
#include "qt/utility/QtThreadedFunctor.h"
#include "qt/window/QtWindowStack.h"
@@ -69,6 +70,8 @@ public:
void forceEnterLicense(bool expired);
void updateHistoryMenu(const std::vector<SearchMatch>& history);
protected:
bool event(QEvent* event);
void keyPressEvent(QKeyEvent* event);
@@ -126,6 +129,8 @@ private slots:
void showBookmarkCreator();
void showBookmarkBrowser();
void openHistoryAction();
private:
struct DockWidget
{
@@ -138,6 +143,7 @@ private:
void setupEditMenu();
void setupProjectMenu();
void setupViewMenu();
void setupHistoryMenu();
void setupBookmarksMenu();
void setupHelpMenu();
@@ -153,6 +159,10 @@ private:
std::vector<DockWidget> m_dockWidgets;
QMenu* m_viewMenu;
QAction* m_viewSeparator;
QMenu* m_historyMenu;
std::vector<SearchMatch> m_history;
QAction** m_recentProjectAction;
QAction* m_showTitleBarsAction;