Mercurial > octave
view libgui/src/resource-manager.cc @ 28422:02a5da73a157
Use std::array rather than std::vector in patch for (bug #54334).
* resource-manager.cc (update_network_settings): Replace std::vector, which can
change size at runtime, with std::array, which does not.
author | Rik <rik@octave.org> |
---|---|
date | Tue, 09 Jun 2020 13:45:20 -0700 |
parents | c648cca864db |
children | 7de12a40e87b |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011-2020 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 <string> #include <QDir> #include <QFile> #include <QLibraryInfo> #include <QMessageBox> #include <QNetworkProxy> #if defined (HAVE_QSTANDARDPATHS) # include <QStandardPaths> #else # include <QDesktopServices> #endif #include <QTextCodec> #include "QTerminal.h" #include "gui-preferences-ed.h" #include "gui-preferences-global.h" #include "octave-qobject.h" #include "resource-manager.h" #include "variable-editor.h" #include "workspace-model.h" #include "file-ops.h" #include "localcharset-wrapper.h" #include "oct-env.h" #include "defaults.h" #include "error.h" #include "help.h" namespace octave { static QString default_qt_settings_file (void) { std::string dsf = sys::env::getenv ("OCTAVE_DEFAULT_QT_SETTINGS"); if (dsf.empty ()) dsf = (config::oct_etc_dir () + sys::file_ops::dir_sep_str () + "default-qt-settings"); return QString::fromStdString (dsf); } resource_manager::resource_manager (void) : m_settings_directory (), m_settings_file (), m_settings (nullptr), m_default_settings (nullptr), m_temporary_files () { // Let gui_settings decide where to put the ini file with gui preferences m_default_settings = new gui_settings (QSettings::IniFormat, QSettings::UserScope, "octave", "octave-gui"); m_settings_file = m_default_settings->fileName (); QFileInfo sfile (m_settings_file); m_settings_directory = sfile.absolutePath (); QString xdg_config_home = QString::fromLocal8Bit (qgetenv ("XDG_CONFIG_HOME")); if ((! sfile.exists ()) && xdg_config_home.isEmpty ()) { // File does not exist yet: Look for a settings file at the old // location ($HOME/.config/octave/qt-settings) for impoting all // available keys into the new settings file. // Do not look for an old settings file if XDG_CONFIG_HOME is set, // since then a nonexistent new settings file does not necessarily // indicate a first run of octave with new config file locations. #if defined (HAVE_QSTANDARDPATHS) QString home_path = QStandardPaths::writableLocation (QStandardPaths::HomeLocation); #else QString home_path = QDesktopServices::storageLocation (QDesktopServices::HomeLocation); #endif QString old_settings_directory = home_path + "/.config/octave"; QString old_settings_file = old_settings_directory + "/qt-settings"; QFile ofile (old_settings_file); if (ofile.exists ()) { // Old settings file exists; create a gui_settings object related // to it and copy all available keys to the new settings gui_settings old_settings (old_settings_file, QSettings::IniFormat); QStringList keys = old_settings.allKeys (); for (int i = 0; i < keys.count(); i++) m_default_settings->setValue (keys.at(i), old_settings.value(keys.at(i))); m_default_settings->sync (); // Done, make sure keys are written } } } resource_manager::~resource_manager (void) { delete m_settings; delete m_default_settings; for (int i = m_temporary_files.count () - 1; i >=0; i--) remove_tmp_file (m_temporary_files.at (i)); } QString resource_manager::get_gui_translation_dir (void) { // get environment variable for the locale dir (e.g. from run-octave) std::string dldir = sys::env::getenv ("OCTAVE_LOCALE_DIR"); if (dldir.empty ()) dldir = config::oct_locale_dir (); // env-var empty, load the default location return QString::fromStdString (dldir); } void resource_manager::config_translators (QTranslator *qt_tr, QTranslator *qsci_tr, QTranslator *gui_tr) { bool loaded; QString qt_trans_dir = QLibraryInfo::location (QLibraryInfo::TranslationsPath); QString language = "SYSTEM"; // take system language per default // FIXME: can we somehow ensure that the settings object will always // be initialize and valid? if (m_settings) { // get the locale from the settings if already available language = m_settings->value (global_language.key, global_language.def).toString (); } // load the translations depending on the settings if (language == "SYSTEM") { // get the system locale and pass it to the translators for loading // the suitable translation files QLocale sys_locale = QLocale::system (); qt_tr->load (sys_locale, "qt", "_", qt_trans_dir); qsci_tr->load (sys_locale, "qscintilla", "_", qt_trans_dir); gui_tr->load (sys_locale, "", "", get_gui_translation_dir ()); } else { // load the translation files depending on the given locale name loaded = qt_tr->load ("qt_" + language, qt_trans_dir); if (! loaded) // try lower case qt_tr->load ("qt_" + language.toLower (), qt_trans_dir); loaded = qsci_tr->load ("qscintilla_" + language, qt_trans_dir); if (! loaded) // try lower case qsci_tr->load ("qscintilla_" + language.toLower (), qt_trans_dir); gui_tr->load (language, get_gui_translation_dir ()); } } gui_settings * resource_manager::get_settings (void) const { return m_settings; } gui_settings * resource_manager::get_default_settings (void) const { return m_default_settings; } QString resource_manager::get_settings_directory (void) { return m_settings_directory; } QString resource_manager::get_settings_file (void) { return m_settings_file; } QString resource_manager::get_default_font_family (void) { // Get the default monospaced font QFont fixed_font; fixed_font.setStyleHint (QFont::Monospace); QString default_family = fixed_font.defaultFamily (); std::string env_default_family = sys::env::getenv ("OCTAVE_DEFAULT_FONT"); if (! env_default_family.empty ()) default_family = QString::fromStdString (env_default_family); return default_family; } void resource_manager::reload_settings (void) { QString default_family = get_default_font_family (); if (! QFile::exists (m_settings_file)) { QDir ("/").mkpath (m_settings_directory); QFile qt_settings (default_qt_settings_file ()); if (! qt_settings.open (QFile::ReadOnly)) return; QTextStream in (&qt_settings); QString settings_text = in.readAll (); qt_settings.close (); default_family = get_default_font_family (); QString default_font_size = "10"; std::string env_default_font_size = sys::env::getenv ("OCTAVE_DEFAULT_FONT_SIZE"); if (! env_default_font_size.empty ()) default_font_size = QString::fromStdString (env_default_font_size); // Get the default custom editor #if defined (Q_OS_WIN32) QString custom_editor = "notepad++ -n%l %f"; #else QString custom_editor = "emacs +%l %f"; #endif std::string env_default_editor = sys::env::getenv ("OCTAVE_DEFAULT_EDITOR"); if (! env_default_editor.empty ()) custom_editor = QString::fromStdString (env_default_editor); // Replace placeholders settings_text.replace ("__default_custom_editor__", custom_editor); settings_text.replace ("__default_font__", default_family); settings_text.replace ("__default_font_size__", default_font_size); QFile user_settings (m_settings_file); if (! user_settings.open (QIODevice::WriteOnly)) return; QTextStream out (&user_settings); out << settings_text; user_settings.close (); } set_settings (m_settings_file); // Write the default monospace font into the settings for later use by // console and editor as fallbacks of their font preferences. if (m_settings) m_settings->setValue (global_mono_font.key, default_family); } void resource_manager::set_settings (const QString& file) { delete m_settings; m_settings = new gui_settings (file, QSettings::IniFormat); if (! (QFile::exists (m_settings->fileName ()) && m_settings->isWritable () && m_settings->status () == QSettings::NoError)) { QString msg = QString (QT_TR_NOOP ("The settings file\n%1\n" "does not exist and can not be created.\n" "Make sure you have read and write permissions to\n%2\n\n" "Octave GUI must be closed now.")); QMessageBox::critical (nullptr, QString (QT_TR_NOOP ("Octave Critical Error")), msg.arg (get_settings_file ()).arg (get_settings_directory ())); exit (1); } } bool resource_manager::update_settings_key (const QString& old_key, const QString& new_key) { if (m_settings->contains (old_key)) { QVariant preference = m_settings->value (old_key); m_settings->setValue (new_key, preference); m_settings->remove (old_key); return true; } return false; } bool resource_manager::is_first_run (void) const { return ! QFile::exists (m_settings_file); } void resource_manager::update_network_settings (void) { if (! m_settings) return; QNetworkProxy proxy; // Assume no proxy and empty proxy data QNetworkProxy::ProxyType proxy_type = QNetworkProxy::NoProxy; QString scheme; QString host; int port = 0; QString user; QString pass; QUrl proxy_url = QUrl (); if (m_settings->value (global_use_proxy.key, global_use_proxy.def).toBool ()) { // Use a proxy, collect all required information QString proxy_type_string = m_settings->value (global_proxy_type.key, global_proxy_type.def).toString (); // The proxy type for the Qt proxy settings if (proxy_type_string == "Socks5Proxy") proxy_type = QNetworkProxy::Socks5Proxy; else if (proxy_type_string == "HttpProxy") proxy_type = QNetworkProxy::HttpProxy; // The proxy data from the settings if (proxy_type_string == "HttpProxy" || proxy_type_string == "Socks5Proxy") { host = m_settings->value (global_proxy_host.key, global_proxy_host.def).toString (); port = m_settings->value (global_proxy_port.key, global_proxy_port.def).toInt (); user = m_settings->value (global_proxy_user.key, global_proxy_user.def).toString (); pass = m_settings->value (global_proxy_pass.key, global_proxy_pass.def).toString (); if (proxy_type_string == "HttpProxy") scheme = "http"; else if (proxy_type_string == "Socks5Proxy") scheme = "socks5"; QUrl env_var_url = QUrl (); proxy_url.setScheme (scheme); proxy_url.setHost (host); proxy_url.setPort (port); if (! user.isEmpty ()) proxy_url.setUserName (user); if (! pass.isEmpty ()) proxy_url.setPassword (pass); } // The proxy data from environment variables if (proxy_type_string == global_proxy_all_types.at (2)) { const std::array<std::string, 6> env_vars = { "ALL_PROXY", "all_proxy", "HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy" }; unsigned int count = 0; while (! proxy_url.isValid () && count < env_vars.size ()) { proxy_url = QUrl (QString::fromStdString (sys::env::getenv (env_vars[count]))); count++; } if (proxy_url.isValid ()) { // Found an entry, get the data from the string scheme = proxy_url.scheme (); if (scheme.contains ("socks", Qt::CaseInsensitive)) proxy_type = QNetworkProxy::Socks5Proxy; else proxy_type = QNetworkProxy::HttpProxy; host = proxy_url.host (); port = proxy_url.port (); user = proxy_url.userName (); pass = proxy_url.password (); } } } // Set proxy for Qt framework proxy.setType (proxy_type); proxy.setHostName (host); proxy.setPort (port); proxy.setUser (user); proxy.setPassword (pass); QNetworkProxy::setApplicationProxy (proxy); // Set proxy for curl library if not based on environment variables std::string proxy_url_str = proxy_url.toString().toStdString (); sys::env::putenv ("http_proxy", proxy_url_str); sys::env::putenv ("HTTP_PROXY", proxy_url_str); sys::env::putenv ("https_proxy", proxy_url_str); sys::env::putenv ("HTTPS_PROXY", proxy_url_str); } QIcon resource_manager::icon (const QString& icon_name, bool fallback) { // If system icon theme is not desired, take own icon files if (! m_settings->value (global_icon_theme).toBool ()) return QIcon (":/actions/icons/" + icon_name + ".png"); // Use system icon theme with own files as fallback except when the // fallback is explicitly disabled (fallback=false) if (fallback) return QIcon::fromTheme (icon_name, QIcon (":/actions/icons/" + icon_name + ".png")); else return QIcon::fromTheme (icon_name); } // get a list of all available encodings void resource_manager::get_codecs (QStringList *codecs) { // get the codec name for each mib QList<int> all_mibs = QTextCodec::availableMibs (); for (auto mib : all_mibs) { QTextCodec *c = QTextCodec::codecForMib (mib); codecs->append (c->name ().toUpper ()); } // Append SYSTEM codecs->append (QString ("SYSTEM (") + QString (octave_locale_charset_wrapper ()).toUpper () + QString (")")); // Clean up and sort list of codecs codecs->removeDuplicates (); qSort (*codecs); } // initialize a given combo box with available text encodings void resource_manager::combo_encoding (QComboBox *combo, const QString& current) { QStringList all_codecs; get_codecs (&all_codecs); // get the value from the settings file if no current encoding is given QString enc = current; // Check for valid codec for the default. If this fails, "SYSTEM" (i.e. // locale_charset) will be chosen. // FIXME: The default is "SYSTEM" on all platforms. So can this fallback // logic be removed completely? bool default_exists = false; if (QTextCodec::codecForName (ed_default_enc.def.toString ().toLatin1 ()) || (ed_default_enc.def.toString ().startsWith ("SYSTEM"))) default_exists = true; QString default_enc = QString ("SYSTEM (") + QString (octave_locale_charset_wrapper ()).toUpper () + QString (")"); if (enc.isEmpty ()) { enc = m_settings->value (ed_default_enc).toString (); if (enc.isEmpty ()) // still empty? { if (default_exists) enc = ed_default_enc.def.toString (); else enc = default_enc; } } // fill the combo box for (const auto& c : all_codecs) combo->addItem (c); // prepend the default item combo->insertSeparator (0); if (default_exists) combo->insertItem (0, ed_default_enc.def.toString ()); else combo->insertItem (0, default_enc); // select the default or the current one int idx = combo->findText (enc, Qt::MatchExactly); if (idx >= 0) combo->setCurrentIndex (idx); else combo->setCurrentIndex (0); combo->setMaxVisibleItems (12); } QPointer<QTemporaryFile> resource_manager::create_tmp_file (const QString& extension, const QString& contents) { QString ext = extension; if ((! ext.isEmpty ()) && (! ext.startsWith ('.'))) ext = QString (".") + ext; // Create octave dir within temp. dir QString tmp_dir = QDir::tempPath () + QDir::separator() + "octave"; QDir::temp ().mkdir ("octave"); // Create temp. file QPointer<QTemporaryFile> tmp_file = new QTemporaryFile (tmp_dir + QDir::separator() + "octave_XXXXXX" + ext, this); if (tmp_file->open ()) { tmp_file->write (contents.toUtf8 ()); tmp_file->close (); m_temporary_files << tmp_file; } return tmp_file; } void resource_manager::remove_tmp_file (QPointer<QTemporaryFile> tmp_file) { if (tmp_file) { if (tmp_file->exists ()) tmp_file->remove (); m_temporary_files.removeAll (tmp_file); } } }