Mercurial > octave
view libgui/src/documentation-bookmarks.cc @ 31619:ad014fc78bd6
use individual local gui_settings objects
Previously, we created a single gui_settings object (derived from
QSettings) and accessed it from the resource_manager object. That
design is not necessary and is not the way QSettings was designed to
be used. Instead of managing a single object, we should be using
individual QSettings objects where needed. Each individual QSettings
object manages thread-safe access to a single global collection of
settings. The Qt docs say that operations on QSettings are not thread
safe, but that means that you can't create a QSettings object in one
thread and use it in another without some locking. I'm not sure
whether we were doing that correctly, but with this change it no
longer matters. Each QSettings object does perform locking when
reading or writing the underlying global data.
* resource-manager.h, resource-manager.cc
(resource_manager::m_settings): Delete data member.
(resource_manager::get_settings): Delete.
* annotation-dialog.cc, QTerminal.cc, QTerminal.h, command-widget.cc,
command-widget.h, community-news.cc, dialog.cc,
documentation-bookmarks.cc, documentation-bookmarks.h,
documentation-dock-widget.cc, documentation-dock-widget.h,
documentation.cc, documentation.h, dw-main-window.cc,
dw-main-window.h, external-editor-interface.cc, files-dock-widget.cc,
files-dock-widget.h, find-files-dialog.cc, history-dock-widget.cc,
history-dock-widget.h, file-editor-interface.h, file-editor-tab.cc,
file-editor-tab.h, file-editor.cc, file-editor.h, find-dialog.cc,
octave-qscintilla.cc, main-window.cc, main-window.h, news-reader.cc,
octave-dock-widget.cc, octave-dock-widget.h, qt-interpreter-events.cc,
qt-interpreter-events.h, release-notes.cc, resource-manager.cc,
resource-manager.h, set-path-dialog.cc, settings-dialog.cc,
settings-dialog.h, shortcut-manager.cc, shortcut-manager.h,
terminal-dock-widget.cc, terminal-dock-widget.h, variable-editor.cc,
variable-editor.h, welcome-wizard.cc, workspace-model.cc,
workspace-model.h, workspace-view.cc: Use local gui_settings objects
instead of accessing a pointer to a single gui_settings object owned
by the resource_manager object.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 02 Dec 2022 14:23:53 -0500 |
parents | 796f54d4ddbf |
children | 0645ea65ca6b |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <QCompleter> #include <QMenu> #include <QShortcut> #include <QVBoxLayout> #include <QWidget> #include "documentation.h" #include "documentation-bookmarks.h" #include "gui-preferences-global.h" #include "gui-preferences-dc.h" #include "gui-preferences-sc.h" #include "gui-settings.h" #include "octave-qtutils.h" #include "shortcut-manager.h" #include "defaults.h" #include "file-ops.h" #include "oct-env.h" namespace octave { documentation_bookmarks::documentation_bookmarks ( documentation *doc, documentation_browser *browser, base_qobject& oct_qobj, QWidget *p) : QWidget (p), m_doc (doc), m_browser (browser), m_octave_qobj (oct_qobj), m_ctx_menu_item (nullptr) { setObjectName ("documentation_tab_bookmarks"); gui_settings settings; // Setup the tree view with the bookmarks m_tree = new QTreeWidget (p); m_tree->setContextMenuPolicy (Qt::CustomContextMenu); m_tree->setSelectionMode (QAbstractItemView::ExtendedSelection); m_tree->setSortingEnabled (false); m_tree->setDragEnabled(true); m_tree->viewport()->setAcceptDrops(true); m_tree->setDropIndicatorShown(true); m_tree->setDragDropMode(QAbstractItemView::InternalMove); m_tree->setColumnCount (1); m_tree->setHeaderHidden (true); m_tree->setEditTriggers (QAbstractItemView::EditKeyPressed | QAbstractItemView::SelectedClicked); connect (m_tree, &QTreeWidget::customContextMenuRequested, this, &documentation_bookmarks::ctx_menu); connect (m_tree, &QTreeWidget::itemDoubleClicked, this, &documentation_bookmarks::handle_double_click); // Define the icons for the tree view icon_folder.addPixmap (style ()->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off); icon_folder.addPixmap (style ()->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On); icon_bookmark.addPixmap (style ()->standardPixmap(QStyle::SP_FileIcon)); // Setup and read the bookmarkfile QFileInfo f (settings.fileName ()); QString f_path = f.absolutePath (); f.setFile (QDir (f_path), dc_bookmark_file); m_xbel_file.setFileName (f.absoluteFilePath ()); if (m_xbel_file.exists ()) { QString err = read_bookmarks (); if ( !err.isEmpty ()) { err.append (tr ("\nNo documentation bookmarks loaded!")); QMessageBox::warning (this, tr ("Octave: Loading Documentation Bookmarks"), err); m_xbel_file.close (); } } // Setup the filter widget m_filter_widget = new QWidget (p); m_filter = new QComboBox (m_filter_widget); m_filter->setToolTip (tr ("Enter text to search the bookmarks")); m_filter->setEditable (true); m_filter->setInsertPolicy (QComboBox::NoInsert); m_filter->setMaxCount (10); m_filter->setMaxVisibleItems (10); m_filter->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon); QSizePolicy size_pol (QSizePolicy::Expanding, QSizePolicy::Preferred); m_filter->setSizePolicy (size_pol); m_filter->completer ()->setCaseSensitivity (Qt::CaseSensitive); m_filter->addItems (settings.value (dc_bookmark_filter_mru).toStringList ()); connect (m_filter, &QComboBox::editTextChanged, this, &documentation_bookmarks::filter_bookmarks); connect (m_filter->lineEdit (), &QLineEdit::editingFinished, this, &documentation_bookmarks::update_filter_history); m_filter_checkbox = new QCheckBox (m_filter_widget); bool filter_state = settings.value (dc_bookmark_filter_active).toBool (); m_filter_checkbox->setChecked (filter_state); filter_activate (filter_state); connect (m_filter_checkbox, &QCheckBox::toggled, this, &documentation_bookmarks::filter_activate); QLabel *filter_label = new QLabel (tr ("Filter"), m_filter_widget); QHBoxLayout *h_box_bm = new QHBoxLayout (m_filter_widget); h_box_bm->addWidget (filter_label); h_box_bm->addWidget (m_filter_checkbox); h_box_bm->addWidget (m_filter); h_box_bm->setMargin (2); m_filter_widget->setLayout (h_box_bm); m_filter_shown = settings.value (dc_bookmark_filter_shown).toBool (); m_filter_widget->setVisible (m_filter_shown); // Resulting Layout of this widget QVBoxLayout *v_box_bm = new QVBoxLayout (this); v_box_bm->addWidget (m_filter_widget); v_box_bm->addWidget (m_tree); setLayout (v_box_bm); } // Slot for adding the current page as a bookmark void documentation_bookmarks::add_bookmark (void) { QUrl url = m_browser->historyUrl (0); // Check if bookmark already exists and select if yes QTreeWidgetItemIterator it (m_tree); while (*it) { QUrl url_i = (*it)->data (0, url_role).toUrl (); if (url == url_i) { m_tree->setCurrentItem (*it); (*it)->setExpanded (true); return; } it++; } // Add the anchor name to the title of the page and add the bookmark // as top-level-item QString title = m_doc->title_and_anchor (m_browser->historyTitle (0), url); add_bookmark (title, url.toString ()); } // Function for actually adding a bookmark to the tree void documentation_bookmarks::add_bookmark (const QString& title, const QString& url, QTreeWidgetItem* item) { // Create new bookmark QTreeWidgetItem *new_item = new QTreeWidgetItem (QStringList (title)); new_item->setData (0, tag_role, QVariant (bookmark_tag)); new_item->setData (0, url_role, QVariant (url)); new_item->setFlags ((new_item->flags () & (~Qt::ItemIsDropEnabled)) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled); new_item->setIcon (0, icon_bookmark); // Insert as top level or child item // TODO: Open dialog allowing to select a target folder if this // bookmark is added manually and not by reading a bookmark file if (item) item->addChild (new_item); else m_tree->addTopLevelItem (new_item); } // Slot for adding a folder from the context menu void documentation_bookmarks::add_folder (bool) { QTreeWidgetItem *parent_item = nullptr; if (m_ctx_menu_item) { if (m_ctx_menu_item->data (0, tag_role).toInt () == folder_tag) parent_item = m_ctx_menu_item; else { QTreeWidgetItem *p = m_ctx_menu_item->parent (); if (p) parent_item = p; } } QTreeWidgetItem *new_folder = add_folder (tr ("New Folder"), parent_item); m_tree->setCurrentItem (new_folder); m_tree->editItem (new_folder); } // Function for actually adding a folder to the tree QTreeWidgetItem* documentation_bookmarks::add_folder (const QString& folder, QTreeWidgetItem *item, bool expanded) { QTreeWidgetItem *new_folder = new QTreeWidgetItem (QStringList (folder)); new_folder->setData (0, tag_role, QVariant (folder_tag)); new_folder->setFlags (new_folder->flags() | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); new_folder->setChildIndicatorPolicy (QTreeWidgetItem::DontShowIndicatorWhenChildless); new_folder->setIcon (0, icon_folder); new_folder->setExpanded (expanded); // Insert as top level or child item if (item) item->addChild (new_folder); else m_tree->addTopLevelItem (new_folder); return new_folder; } void documentation_bookmarks::filter_bookmarks (const QString& pattern) { QTreeWidgetItemIterator it (m_tree); while (*it) { if ((*it)->text (0).contains (pattern, Qt::CaseInsensitive)) { (*it)->setHidden (false); (*it)->setExpanded (true); QTreeWidgetItem *p = (*it)->parent (); while (p) { p->setHidden (false); p->setExpanded (true); p = p->parent (); } } else (*it)->setHidden (true); it++; } } void documentation_bookmarks::filter_activate (bool state) { m_filter->setEnabled (state); QString pattern; if (state) pattern = m_filter->currentText (); filter_bookmarks (pattern); } void documentation_bookmarks::update_filter_history (void) { QString text = m_filter->currentText (); // get current text int index = m_filter->findText (text); // and its actual index if (index > -1) m_filter->removeItem (index); // remove if already existing m_filter->insertItem (0, text); // (re)insert at beginning m_filter->setCurrentIndex (0); } void documentation_bookmarks::handle_double_click (QTreeWidgetItem *item, int) { int tag = item->data (0, tag_role).toInt (); if (tag == folder_tag) { item->setExpanded (! item->isExpanded ()); return; } if (tag == bookmark_tag) { QUrl url = item->data (0, url_role).toUrl (); if (! url.isEmpty ()) m_browser->setSource (url); return; } } void documentation_bookmarks::ctx_menu (const QPoint& xpos) { QMenu menu (this); m_ctx_menu_item = m_tree->itemAt (xpos); if (m_ctx_menu_item) { resource_manager& rmgr = m_octave_qobj.get_resource_manager (); menu.addAction (tr ("&Open"), this, &documentation_bookmarks::open); menu.addAction (tr ("&Rename"), this, &documentation_bookmarks::edit); menu.addAction (rmgr.icon ("window-close"), tr ("Remo&ve"), this, &documentation_bookmarks::remove); menu.addSeparator (); } menu.addAction (tr ("&Add Folder"), this, QOverload<bool>::of (&documentation_bookmarks::add_folder)); menu.addSeparator (); if (m_filter_shown) menu.addAction (tr ("Hide &Filter"), this, &documentation_bookmarks::show_filter); else menu.addAction (tr ("Show &Filter"), this, &documentation_bookmarks::show_filter); menu.exec (m_tree->mapToGlobal (xpos)); } void documentation_bookmarks::open (bool) { QList<QTreeWidgetItem *> items = m_tree->selectedItems (); if (items.size () > 0) handle_double_click (items.at (0)); } void documentation_bookmarks::edit (bool) { QList<QTreeWidgetItem *> items = m_tree->selectedItems (); if (items.size () > 0) m_tree->editItem (items.at (0)); } void documentation_bookmarks::remove (bool) { QList<QTreeWidgetItem *> items = m_tree->selectedItems (); for (auto it = items.begin () ; it != items.end (); it++) { if (*it) m_tree->takeTopLevelItem ( m_tree->indexOfTopLevelItem (*it)); } } void documentation_bookmarks::show_filter (bool) { m_filter_shown = ! m_filter_shown; m_filter_widget->setVisible (m_filter_shown); } void documentation_bookmarks::save_settings (void) { // Write the bookmarks to the xbel-file write_bookmarks (); // Store settings gui_settings settings; settings.setValue (dc_bookmark_filter_active.key, m_filter_checkbox->isChecked ()); settings.setValue (dc_bookmark_filter_shown.key, m_filter_shown); QStringList mru; for (int i = 0; i < m_filter->count (); i++) mru.append (m_filter->itemText (i)); settings.setValue (dc_bookmark_filter_mru.key, mru); settings.sync (); } void documentation_bookmarks::write_bookmarks (void) { if (! m_xbel_file.open (QFile::WriteOnly | QFile::Text)) { QMessageBox::warning (this, tr("Octave: Saving Documentation Bookmarks"), tr("Unable to write file %1:\n%2.\n\n" "Documentation bookmarks are not saved!\n") .arg (m_xbel_file.fileName ()) .arg (m_xbel_file.errorString())); return; } QXmlStreamWriter xml_writer (&m_xbel_file); xml_writer.setAutoFormatting (true); xml_writer.writeStartDocument (); xml_writer.writeDTD (dc_xbel_doctype); xml_writer.writeStartElement (dc_xbel_name_format); xml_writer.writeAttribute (dc_xbel_attr_version, dc_xbel_value_version); for (int i = 0; i < m_tree->topLevelItemCount(); i++) write_tree_item (&xml_writer, m_tree->topLevelItem (i)); xml_writer.writeEndDocument(); m_xbel_file.flush (); m_xbel_file.close (); } void documentation_bookmarks::write_tree_item (QXmlStreamWriter* xml_writer, const QTreeWidgetItem *item) { switch (item->data (0, tag_role).toInt ()) { case folder_tag: xml_writer->writeStartElement (dc_xbel_name_folder); xml_writer->writeAttribute (dc_xbel_attr_folded, item->isExpanded () ? dc_xbel_value_no : dc_xbel_value_yes); xml_writer->writeTextElement (dc_xbel_name_title, item->text(0)); for (int i = 0; i < item->childCount (); i++) write_tree_item (xml_writer, item->child (i)); xml_writer->writeEndElement (); break; case bookmark_tag: xml_writer->writeStartElement (dc_xbel_name_bookmark); xml_writer->writeAttribute (dc_xbel_attr_href, item->data (0, url_role).toString ()); xml_writer->writeTextElement (dc_xbel_name_title, item->text (0)); xml_writer->writeEndElement (); break; } } QString documentation_bookmarks::read_bookmarks (void) { QString error_message; // Check the file if (! m_xbel_file.open (QFile::ReadOnly | QFile::Text)) { error_message = tr ("Unable to read file %1:\n%2.") .arg (m_xbel_file.fileName ()) .arg (m_xbel_file.errorString()); return error_message; } QXmlStreamReader xml_reader (&m_xbel_file); if (! xml_reader.readNextStartElement ()) { error_message = tr ("No start element found in %1.\n" "Invalid bookmark file?") .arg (m_xbel_file.fileName ()); return error_message; } if (xml_reader.name() != dc_xbel_name_format || xml_reader.attributes ().value (dc_xbel_attr_version) != dc_xbel_value_version) { error_message = tr ("The file\n" "%1\n" "is not a valid XBEL file version 1.0.") .arg (m_xbel_file.fileName ()); return error_message; } // Read the elements from the file while (xml_reader.readNextStartElement ()) { if (xml_reader.name () == dc_xbel_name_folder) read_next_item (&xml_reader, folder_tag); else if (xml_reader.name () == dc_xbel_name_bookmark) read_next_item (&xml_reader, bookmark_tag); else xml_reader.skipCurrentElement (); } m_xbel_file.close (); return error_message; } void documentation_bookmarks::read_next_item (QXmlStreamReader *xml_reader, item_tag tag, QTreeWidgetItem *item) { QString title (tr ("Unknown title")); if (tag == folder_tag) { // Next item is a folder, which might also have children bool expanded = (xml_reader->attributes().value (dc_xbel_attr_folded) == dc_xbel_value_no); QTreeWidgetItem *new_folder = add_folder (title, item, expanded); // Check elements of this folder for title and for recursively // adding sub-items while (xml_reader->readNextStartElement ()) { if (xml_reader->name () == dc_xbel_name_title) { title = xml_reader->readElementText(); new_folder->setText (0, title); } else if (xml_reader->name () == dc_xbel_name_folder) read_next_item (xml_reader, folder_tag, new_folder); else if (xml_reader->name () == dc_xbel_name_bookmark) read_next_item (xml_reader, bookmark_tag, new_folder); else xml_reader->skipCurrentElement (); } } else if (tag == bookmark_tag) { // Next item is a bookmark, without children QString url = xml_reader->attributes().value (dc_xbel_attr_href).toString (); while (xml_reader->readNextStartElement ()) { if (xml_reader->name() == dc_xbel_name_title) title = xml_reader->readElementText(); else xml_reader->skipCurrentElement (); } add_bookmark (title, url, item); } } }