more documentation and exportthread restructure
This commit is contained in:
+100
-3
@@ -30,63 +30,133 @@
|
||||
ActionSearch::ActionSearch(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
// ActionSearch requires a parent widget
|
||||
Q_ASSERT(parent != nullptr);
|
||||
|
||||
// Set styling (object name is required for CSS specific to this object)
|
||||
setObjectName("ASDiag");
|
||||
setStyleSheet("#ASDiag{border: 2px solid #808080;}");
|
||||
|
||||
// Size proportionally to the parent (usually MainWindow).
|
||||
resize(parent->width()/3, parent->height()/3);
|
||||
|
||||
// Show dialog as a "popup", which will make the dialog close if the user clicks out of it.
|
||||
setWindowFlags(Qt::Popup);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
// Construct the main entry text field.
|
||||
ActionSearchEntry* entry_field = new ActionSearchEntry(this);
|
||||
|
||||
// Set the main entry field font size to 1.2x its standard font size.
|
||||
QFont entry_field_font = entry_field->font();
|
||||
entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2));
|
||||
entry_field->setFont(entry_field_font);
|
||||
|
||||
// Set placeholder text for the main entry field
|
||||
entry_field->setPlaceholderText(tr("Search for action..."));
|
||||
|
||||
// Connect signals/slots
|
||||
connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &)));
|
||||
connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action()));
|
||||
|
||||
// moveSelectionUp() and moveSelectionDown() are emitted when the user pressed up or down on the text field.
|
||||
// We override it here to select the upper or lower item in the list.
|
||||
connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up()));
|
||||
connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down()));
|
||||
layout->addWidget(entry_field);
|
||||
|
||||
// Construct list of actions
|
||||
list_widget = new ActionSearchList(this);
|
||||
|
||||
// Set list's font to 1.2x its standard font size
|
||||
QFont list_widget_font = list_widget->font();
|
||||
list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2));
|
||||
list_widget->setFont(list_widget_font);
|
||||
|
||||
layout->addWidget(list_widget);
|
||||
|
||||
connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action()));
|
||||
|
||||
// Instantly focus on the entry field to allow for fully keyboard operation (if this popup was initiated by keyboard
|
||||
// shortcut for example).
|
||||
entry_field->setFocus();
|
||||
}
|
||||
|
||||
void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent) {
|
||||
|
||||
// This function is recursive, using the `parent` parameter to loop through a menu's items. It functions in two
|
||||
// modes - the parent being NULL, meaning it'll get MainWindow's menubar and loop over its menus, and the parent
|
||||
// referring to a menu at which point it'll loop over its actions (and call itself recursively if it finds any
|
||||
// submenus).
|
||||
|
||||
if (parent == nullptr) {
|
||||
|
||||
// If parent is NULL, we'll pull from the MainWindow's menubar and call this recursively on all of its submenus
|
||||
// (and their submenus).
|
||||
|
||||
// We'll clear all the current items in the list since if we're here, we're just starting.
|
||||
list_widget->clear();
|
||||
QList<QAction*> menus = olive::MainWindow->menuBar()->actions();
|
||||
|
||||
QList<QAction*> menus = olive::MainWindow->menuBar()->actions();
|
||||
|
||||
// Loop through all menus from the menubar and run this function on each one.
|
||||
for (int i=0;i<menus.size();i++) {
|
||||
QMenu* menu = menus.at(i)->menu();
|
||||
|
||||
search_update(s, p, menu);
|
||||
}
|
||||
if (list_widget->count() > 0)
|
||||
|
||||
// Once we're here, all the recursion/item retrieval is complete. We auto-select the first item for better
|
||||
// keyboard-exclusive functionality.
|
||||
if (list_widget->count() > 0) {
|
||||
list_widget->item(0)->setSelected(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Parent was not NULL, so we loop over the actions in the menu we were given in `parent`.
|
||||
|
||||
// The list shows a '>' delimited hierarchy of the menus in which this action came from. We construct it here by
|
||||
// adding the current menu's text to the existing hierarchy (passed in `p`).
|
||||
QString menu_text;
|
||||
if (!p.isEmpty()) menu_text += p + " > ";
|
||||
menu_text += parent->title().replace("&", "");
|
||||
menu_text += parent->title().replace("&", ""); // Strip out any &s used in menu action names
|
||||
|
||||
// Loop over the menu's actions
|
||||
QList<QAction*> actions = parent->actions();
|
||||
for (int i=0;i<actions.size();i++) {
|
||||
|
||||
QAction* a = actions.at(i);
|
||||
|
||||
// Ignore separator actions
|
||||
if (!a->isSeparator()) {
|
||||
|
||||
if (a->menu() != nullptr) {
|
||||
|
||||
// If the action is a menu, run this function recursively on it
|
||||
search_update(s, menu_text, a->menu());
|
||||
|
||||
} else {
|
||||
|
||||
// This is a valid non-separator non-menu action, so check it against the currently entered string.
|
||||
|
||||
// Strip out all &s from the action's name
|
||||
QString comp = a->text().replace("&", "");
|
||||
|
||||
// See if the action's name contains any of the currently entered string
|
||||
if (comp.contains(s, Qt::CaseInsensitive)) {
|
||||
|
||||
// If so, we add it to the list widget.
|
||||
QListWidgetItem* item = new QListWidgetItem(QString("%1\n(%2)").arg(comp, menu_text), list_widget);
|
||||
|
||||
// Add a pointer to the original QAction in the item's data
|
||||
item->setData(Qt::UserRole+1, reinterpret_cast<quintptr>(a));
|
||||
|
||||
list_widget->addItem(item);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,16 +164,31 @@ void ActionSearch::search_update(const QString &s, const QString &p, QMenu *pare
|
||||
}
|
||||
|
||||
void ActionSearch::perform_action() {
|
||||
|
||||
// Loop over all the items in the list and if we find one that's selected, we trigger it.
|
||||
QList<QListWidgetItem*> selected_items = list_widget->selectedItems();
|
||||
if (list_widget->count() > 0 && selected_items.size() > 0) {
|
||||
|
||||
QListWidgetItem* item = selected_items.at(0);
|
||||
|
||||
// Get QAction pointer from item's data
|
||||
QAction* a = reinterpret_cast<QAction*>(item->data(Qt::UserRole+1).value<quintptr>());
|
||||
|
||||
a->trigger();
|
||||
|
||||
}
|
||||
|
||||
// Close this popup
|
||||
accept();
|
||||
|
||||
}
|
||||
|
||||
void ActionSearch::move_selection_up() {
|
||||
|
||||
// Here we loop over all the items to find the currently selected one, and then select the one above it. We start
|
||||
// iterating at 1 (instead of 0) to efficiently ignore the first item (since the selection can't go below the very
|
||||
// bottom item).
|
||||
|
||||
int lim = list_widget->count();
|
||||
for (int i=1;i<lim;i++) {
|
||||
if (list_widget->item(i)->isSelected()) {
|
||||
@@ -115,6 +200,11 @@ void ActionSearch::move_selection_up() {
|
||||
}
|
||||
|
||||
void ActionSearch::move_selection_down() {
|
||||
|
||||
// Here we loop over all the items to find the currently selected one, and then select the one below it. We limit it
|
||||
// one entry before count() to efficiently ignore the item at the end (since the selection can't go below the very
|
||||
// bottom item).
|
||||
|
||||
int lim = list_widget->count()-1;
|
||||
for (int i=0;i<lim;i++) {
|
||||
if (list_widget->item(i)->isSelected()) {
|
||||
@@ -128,6 +218,9 @@ void ActionSearch::move_selection_down() {
|
||||
ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {}
|
||||
|
||||
void ActionSearchEntry::keyPressEvent(QKeyEvent * event) {
|
||||
|
||||
// Listen for up/down, otherwise pass the key event to the base class.
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Up:
|
||||
emit moveSelectionUp();
|
||||
@@ -138,10 +231,14 @@ void ActionSearchEntry::keyPressEvent(QKeyEvent * event) {
|
||||
default:
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {}
|
||||
|
||||
void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) {
|
||||
|
||||
// Indiscriminately emit a signal on any double click
|
||||
emit dbl_click();
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user