]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt/GuiPrefs.cpp
Hack to display section symbol
[lyx.git] / src / frontends / qt / GuiPrefs.cpp
index be6204ba2904cb8ada5f5f550539de22ba8df027..a5f4014874772d747b61ddaa73e0c1b974705b66 100644 (file)
@@ -31,9 +31,9 @@
 #include "ConverterCache.h"
 #include "FontEnums.h"
 #include "FuncRequest.h"
-#include "KeyMap.h"
 #include "KeySequence.h"
 #include "Language.h"
+#include "LengthCombo.h"
 #include "LyXAction.h"
 #include "LyX.h"
 #include "PanelStack.h"
@@ -50,8 +50,6 @@
 #include "support/os.h"
 #include "support/Package.h"
 
-#include "graphics/GraphicsTypes.h"
-
 #include "frontends/alert.h"
 #include "frontends/Application.h"
 #include "frontends/FontLoader.h"
@@ -191,7 +189,7 @@ QString browseRelToSub(QString const & filename, QString const & relpath,
                toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
 
        QString testname = reloutname;
-       testname.remove(QRegExp("^(\\.\\./)+"));
+       testname.remove(QRegularExpression("^(\\.\\./)+"));
 
        if (testname.contains("/"))
                return outname;
@@ -224,7 +222,7 @@ static void parseFontName(QString const & mangled0,
                name = mangled;
                foundry.clear();
        } else {
-               name = mangled.substr(0, idx - 1),
+               name = mangled.substr(0, idx - 1);
                foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
        }
 }
@@ -317,7 +315,7 @@ static void setComboxFont(QComboBox * cb, string const & family,
 /////////////////////////////////////////////////////////////////////
 
 PrefOutput::PrefOutput(GuiPreferences * form)
-       : PrefModule(catOutput, N_("General"), form)
+       : PrefModule(catOutput, N_("General[[settings]]"), form)
 {
        setupUi(this);
 
@@ -436,13 +434,11 @@ PrefInput::PrefInput(GuiPreferences * form)
                this, SIGNAL(changed()));
 
        // reveal checkbox for switching Ctrl and Meta on Mac:
-       bool swapcb = false;
 #ifdef Q_OS_MAC
-#if QT_VERSION > 0x040600
-       swapcb = true;
-#endif
+       dontswapCB->setVisible(true);
+#else
+       dontswapCB->setVisible(false);
 #endif
-       dontswapCB->setVisible(swapcb);
 }
 
 
@@ -914,26 +910,48 @@ PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
 {
        setupUi(this);
 
+#if QT_VERSION < 0x050e00
        connect(screenRomanCO, SIGNAL(activated(QString)),
                this, SLOT(selectRoman(QString)));
        connect(screenSansCO, SIGNAL(activated(QString)),
                this, SLOT(selectSans(QString)));
        connect(screenTypewriterCO, SIGNAL(activated(QString)),
                this, SLOT(selectTypewriter(QString)));
+#else
+       connect(screenRomanCO, SIGNAL(textActivated(QString)),
+               this, SLOT(selectRoman(QString)));
+       connect(screenSansCO, SIGNAL(textActivated(QString)),
+               this, SLOT(selectSans(QString)));
+       connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
+               this, SLOT(selectTypewriter(QString)));
+#endif
 
+#if QT_VERSION >= 0x060000
+       const QStringList families(QFontDatabase::families());
+#else
        QFontDatabase fontdb;
-       QStringList families(fontdb.families());
-       for (QStringList::Iterator it = families.begin(); it != families.end(); ++it) {
-               screenRomanCO->addItem(*it);
-               screenSansCO->addItem(*it);
-               screenTypewriterCO->addItem(*it);
+       const QStringList families(fontdb.families());
+#endif
+       for (auto const & family : families) {
+               screenRomanCO->addItem(family);
+               screenSansCO->addItem(family);
+               screenTypewriterCO->addItem(family);
        }
+#if QT_VERSION < 0x050e00
        connect(screenRomanCO, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
        connect(screenSansCO, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
        connect(screenTypewriterCO, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
+#else
+       connect(screenRomanCO, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+       connect(screenSansCO, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+       connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+#endif
        connect(screenZoomSB, SIGNAL(valueChanged(int)),
                this, SIGNAL(changed()));
        connect(screenTinyED, SIGNAL(textChanged(QString)),
@@ -1089,7 +1107,7 @@ PrefColors::PrefColors(GuiPreferences * form)
                        continue;
                lcolors_.push_back(lc);
        }
-       qSort(lcolors_.begin(), lcolors_.end(), ColorSorter);
+       sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
        vector<ColorCode>::const_iterator cit = lcolors_.begin();
        vector<ColorCode>::const_iterator const end = lcolors_.end();
        for (; cit != end; ++cit) {
@@ -1134,7 +1152,7 @@ void PrefColors::applyRC(LyXRC & rc) const
 void PrefColors::updateRC(LyXRC const & rc)
 {
        for (size_type i = 0; i < lcolors_.size(); ++i) {
-               QColor color = QColor(guiApp->colorCache().get(lcolors_[i], false));
+               QColor color = guiApp->colorCache().get(lcolors_[i], false);
                QPixmap coloritem(32, 32);
                coloritem.fill(color);
                lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
@@ -1207,8 +1225,8 @@ void PrefColors::resetAllColor()
 }
 
 
-bool PrefColors::setColor(int const row, QColor const new_color,
-                         QString const old_color)
+bool PrefColors::setColor(int const row, QColor const new_color,
+                         QString const old_color)
 {
        if (new_color.isValid() && new_color.name() != old_color) {
                newcolors_[size_t(row)] = new_color.name();
@@ -1245,7 +1263,7 @@ void PrefColors::setDisabledResets()
 }
 
 
-bool PrefColors::isDefaultColor(int const row, QString const color)
+bool PrefColors::isDefaultColor(int const row, QString const color)
 {
        return color == getDefaultColorByRow(row).name();
 }
@@ -1254,7 +1272,8 @@ bool PrefColors::isDefaultColor(int const row, QString const color)
 QColor PrefColors::getDefaultColorByRow(int const row)
 {
        ColorSet const defaultcolor;
-       return defaultcolor.getX11Name(lcolors_[size_t(row)]).c_str();
+       return defaultcolor.getX11HexName(lcolors_[size_t(row)],
+                       guiApp->colorCache().isDarkMode()).c_str();
 }
 
 
@@ -1303,6 +1322,7 @@ PrefDisplay::PrefDisplay(GuiPreferences * form)
        connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
        connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
        connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
+       connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
 }
 
 
@@ -1329,6 +1349,7 @@ void PrefDisplay::applyRC(LyXRC & rc) const
        rc.display_graphics = displayGraphicsCB->isChecked();
        rc.preview_scale_factor = previewSizeSB->value();
        rc.paragraph_markers = paragraphMarkerCB->isChecked();
+       rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
 
        // FIXME!! The graphics cache no longer has a changeDisplay method.
 #if 0
@@ -1357,6 +1378,7 @@ void PrefDisplay::updateRC(LyXRC const & rc)
        displayGraphicsCB->setChecked(rc.display_graphics);
        previewSizeSB->setValue(rc.preview_scale_factor);
        paragraphMarkerCB->setChecked(rc.paragraph_markers);
+       ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
        previewSizeSB->setEnabled(
                rc.display_graphics
                && rc.preview != LyXRC::PREVIEW_OFF);
@@ -1636,10 +1658,17 @@ PrefConverters::PrefConverters(GuiPreferences * form)
                this, SLOT(updateConverter()));
        connect(convertersLW, SIGNAL(currentRowChanged(int)),
                this, SLOT(switchConverter()));
+#if QT_VERSION < 0x050e00
        connect(converterFromCO, SIGNAL(activated(QString)),
                this, SLOT(changeConverter()));
        connect(converterToCO, SIGNAL(activated(QString)),
                this, SLOT(changeConverter()));
+#else
+       connect(converterFromCO, SIGNAL(textActivated(QString)),
+               this, SLOT(changeConverter()));
+       connect(converterToCO, SIGNAL(textActivated(QString)),
+               this, SLOT(changeConverter()));
+#endif
        connect(converterED, SIGNAL(textEdited(QString)),
                this, SLOT(changeConverter()));
        connect(converterFlagED, SIGNAL(textEdited(QString)),
@@ -1857,7 +1886,7 @@ void PrefConverters::on_needauthCB_toggled(bool checked)
        }
 
        int ret = frontend::Alert::prompt(
-               _("SECURITY WARNING!"), _("Unchecking this option has the effect that potentially harmful converters would be run without asking your permission first. This is UNSAFE and NOT recommended, unless you know what you are doing. Are you sure you would like to proceed ? The recommended and safe answer is NO!"),
+               _("SECURITY WARNING!"), _("Unchecking this option has the effect that potentially harmful converters would be run without asking your permission first. This is UNSAFE and NOT recommended, unless you know what you are doing. Are you sure you would like to proceed? The recommended and safe answer is NO!"),
                0, 0, _("&No"), _("&Yes"));
        if (ret == 1)
                changed();
@@ -1876,8 +1905,8 @@ class FormatValidator : public QValidator
 {
 public:
        FormatValidator(QWidget *, Formats const & f);
-       void fixup(QString & input) const;
-       QValidator::State validate(QString & input, int & pos) const;
+       void fixup(QString & input) const override;
+       QValidator::State validate(QString & input, int & pos) const override;
 private:
        virtual QString toString(Format const & format) const = 0;
        int nr() const;
@@ -1943,7 +1972,7 @@ public:
                : FormatValidator(parent, f)
        {}
 private:
-       QString toString(Format const & format) const
+       QString toString(Format const & format) const override
        {
                return toqstr(format.name());
        }
@@ -1963,7 +1992,7 @@ public:
                : FormatValidator(parent, f)
        {}
 private:
-       QString toString(Format const & format) const
+       QString toString(Format const & format) const override
        {
                return toqstr(translateIfPossible(format.prettyname()));
        }
@@ -1999,12 +2028,21 @@ PrefFileformats::PrefFileformats(GuiPreferences * form)
                this, SLOT(updatePrettyname()));
        connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
                this, SIGNAL(changed()));
+#if QT_VERSION < 0x050e00
        connect(defaultFormatCB, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
        connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
        connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
                this, SIGNAL(changed()));
+#else
+       connect(defaultFormatCB, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+       connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+       connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
+               this, SIGNAL(changed()));
+#endif
        connect(viewerCO, SIGNAL(activated(int)),
                this, SIGNAL(changed()));
        connect(editorCO, SIGNAL(activated(int)),
@@ -2282,6 +2320,8 @@ void PrefFileformats::updateViewers()
        viewerCO->blockSignals(true);
        viewerCO->clear();
        viewerCO->addItem(qt_("None"), QString());
+       if (os::canAutoOpenFile(f.extension(), os::VIEW))
+               viewerCO->addItem(qt_("System Default"), QString("auto"));
        updateComboBox(viewer_alternatives, f.name(), viewerCO);
        viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
        viewerCO->blockSignals(false);
@@ -2305,6 +2345,8 @@ void PrefFileformats::updateEditors()
        editorCO->blockSignals(true);
        editorCO->clear();
        editorCO->addItem(qt_("None"), QString());
+       if (os::canAutoOpenFile(f.extension(), os::EDIT))
+               editorCO->addItem(qt_("System Default"), QString("auto"));
        updateComboBox(editor_alternatives, f.name(), editorCO);
        editorCO->addItem(qt_("Custom"), QString("custom editor"));
        editorCO->blockSignals(false);
@@ -2423,7 +2465,7 @@ PrefLanguage::PrefLanguage(GuiPreferences * form)
        startCommandED->setValidator(new NoNewLineValidator(startCommandED));
        endCommandED->setValidator(new NoNewLineValidator(endCommandED));
 
-       defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
+       defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
        defaultDecimalSepED->setMaxLength(1);
 
        defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
@@ -2452,6 +2494,9 @@ PrefLanguage::PrefLanguage(GuiPreferences * form)
                                      index.data(Qt::UserRole).toString());
        }
        uiLanguageCO->blockSignals(false);
+
+       // FIXME: restore this when it works (see discussion in #6450).
+       respectOSkbdCB->hide();
 }
 
 
@@ -2574,15 +2619,25 @@ PrefUserInterface::PrefUserInterface(GuiPreferences * form)
                this, SIGNAL(changed()));
        connect(tooltipCB, SIGNAL(toggled(bool)),
                this, SIGNAL(changed()));
+       connect(toggleTabbarCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
+       connect(toggleMenubarCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
+       connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
+       connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
+       connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
        lastfilesSB->setMaximum(maxlastfiles);
 
        iconSetCO->addItem(qt_("Default"), QString());
        iconSetCO->addItem(qt_("Classic"), "classic");
        iconSetCO->addItem(qt_("Oxygen"), "oxygen");
 
-#if (!(defined Q_WS_X11 || defined(QPA_XCB)) || QT_VERSION < 0x040600)
-       useSystemThemeIconsCB->hide();
-#endif
+       if (guiApp->platformName() != "xcb"
+           && !guiApp->platformName().contains("wayland"))
+               useSystemThemeIconsCB->hide();
 }
 
 
@@ -2595,6 +2650,11 @@ void PrefUserInterface::applyRC(LyXRC & rc) const
        rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
        rc.num_lastfiles = lastfilesSB->value();
        rc.use_tooltip = tooltipCB->isChecked();
+       rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
+       rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
+       rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
+       rc.full_screen_tabbar = toggleTabbarCB->isChecked();
+       rc.full_screen_menubar = toggleMenubarCB->isChecked();
 }
 
 
@@ -2608,6 +2668,11 @@ void PrefUserInterface::updateRC(LyXRC const & rc)
        uiFileED->setText(toqstr(external_path(rc.ui_file)));
        lastfilesSB->setValue(rc.num_lastfiles);
        tooltipCB->setChecked(rc.use_tooltip);
+       toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
+       toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
+       toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
+       toggleTabbarCB->setChecked(rc.full_screen_tabbar);
+       toggleMenubarCB->setChecked(rc.full_screen_menubar);
 }
 
 
@@ -2716,6 +2781,21 @@ void PrefDocHandling::updateRC(LyXRC const & rc)
                closeLastViewCO->setCurrentIndex(1);
        else if (rc.close_buffer_with_last_view == "ask")
                closeLastViewCO->setCurrentIndex(2);
+       if (rc.backupdir_path.empty())
+               backupCB->setToolTip(qt_("If this is checked, a backup of the document is created "
+                                        "in the current working directory. "
+                                        "The backup file has the same name but the suffix '.lyx~'. "
+                                        "Note that these files are hidden by default by some file managers. "
+                                        "A dedicated backup directory can be set in the 'Paths' section."));
+       else {
+               docstring const tip = bformat(_("If this is checked, a backup of the document is created "
+                                               "in the backup directory (%1$s). "
+                                               "The backup file has the full original path and name as file name "
+                                               "and the suffix \'.lyx~\' (e.g., !mydir!filename.lyx~). "
+                                               "Note that these files are hidden by default by some file managers."),
+                                             FileName(rc.backupdir_path).absoluteFilePath());
+               backupCB->setToolTip(toqstr(tip));
+       }
 }
 
 
@@ -2743,6 +2823,8 @@ PrefEdit::PrefEdit(GuiPreferences * form)
                this, SIGNAL(changed()));
        connect(macLikeCursorMovementCB, SIGNAL(clicked()),
                this, SIGNAL(changed()));
+       connect(copyCTMarkupCB, SIGNAL(clicked()),
+               this, SIGNAL(changed()));
        connect(sortEnvironmentsCB, SIGNAL(clicked()),
                this, SIGNAL(changed()));
        connect(groupEnvironmentsCB, SIGNAL(clicked()),
@@ -2751,28 +2833,37 @@ PrefEdit::PrefEdit(GuiPreferences * form)
                this, SIGNAL(changed()));
        connect(cursorWidthSB, SIGNAL(valueChanged(int)),
                this, SIGNAL(changed()));
-       connect(fullscreenLimitGB, SIGNAL(clicked()),
-               this, SIGNAL(changed()));
-       connect(fullscreenWidthSB, SIGNAL(valueChanged(int)),
-               this, SIGNAL(changed()));
-       connect(toggleTabbarCB, SIGNAL(toggled(bool)),
-               this, SIGNAL(changed()));
-       connect(toggleMenubarCB, SIGNAL(toggled(bool)),
-               this, SIGNAL(changed()));
-       connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
+       connect(citationSearchLE, SIGNAL(textChanged(QString)),
                this, SIGNAL(changed()));
-       connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
+       connect(screenWidthLE, SIGNAL(textChanged(QString)),
                this, SIGNAL(changed()));
-       connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
+       connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)), 
                this, SIGNAL(changed()));
 }
 
 
+void PrefEdit::on_screenLimitCB_toggled(bool const state)
+{
+       screenWidthLE->setEnabled(state);
+       screenWidthUnitCO->setEnabled(state);
+       changed();
+}
+
+
+void PrefEdit::on_citationSearchCB_toggled(bool const state)
+{
+       citationSearchLE->setEnabled(state);
+       citationSearchLA->setEnabled(state);
+       changed();
+}
+
+
 void PrefEdit::applyRC(LyXRC & rc) const
 {
        rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
        rc.scroll_below_document = scrollBelowCB->isChecked();
        rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
+       rc.ct_markup_copied = copyCTMarkupCB->isChecked();
        rc.sort_layouts = sortEnvironmentsCB->isChecked();
        rc.group_layouts = groupEnvironmentsCB->isChecked();
        switch (macroEditStyleCO->currentIndex()) {
@@ -2781,13 +2872,10 @@ void PrefEdit::applyRC(LyXRC & rc) const
                case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST;   break;
        }
        rc.cursor_width = cursorWidthSB->value();
-       rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
-       rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
-       rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
-       rc.full_screen_tabbar = toggleTabbarCB->isChecked();
-       rc.full_screen_menubar = toggleMenubarCB->isChecked();
-       rc.full_screen_width = fullscreenWidthSB->value();
-       rc.full_screen_limit = fullscreenLimitGB->isChecked();
+       rc.citation_search = citationSearchCB->isChecked();
+       rc.citation_search_pattern = fromqstr(citationSearchLE->text());
+       rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO)); 
+       rc.screen_limit = screenLimitCB->isChecked(); 
 }
 
 
@@ -2796,17 +2884,19 @@ void PrefEdit::updateRC(LyXRC const & rc)
        cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
        scrollBelowCB->setChecked(rc.scroll_below_document);
        macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
+       copyCTMarkupCB->setChecked(rc.ct_markup_copied);
        sortEnvironmentsCB->setChecked(rc.sort_layouts);
        groupEnvironmentsCB->setChecked(rc.group_layouts);
        macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
        cursorWidthSB->setValue(rc.cursor_width);
-       toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
-       toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
-       toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
-       toggleTabbarCB->setChecked(rc.full_screen_tabbar);
-       toggleMenubarCB->setChecked(rc.full_screen_menubar);
-       fullscreenWidthSB->setValue(rc.full_screen_width);
-       fullscreenLimitGB->setChecked(rc.full_screen_limit);
+       citationSearchCB->setChecked(rc.citation_search);
+       citationSearchLE->setText(toqstr(rc.citation_search_pattern));
+       citationSearchLE->setEnabled(rc.citation_search);
+       citationSearchLA->setEnabled(rc.citation_search);
+       lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
+       screenWidthUnitCO->setEnabled(rc.screen_limit);
+       screenLimitCB->setChecked(rc.screen_limit);
+       screenWidthLE->setEnabled(rc.screen_limit);
 }
 
 
@@ -2821,13 +2911,14 @@ GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
 {
        Ui::shortcutUi::setupUi(this);
        QDialog::setModal(true);
+       lfunLE->setValidator(new NoNewLineValidator(lfunLE));
 }
 
 
 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
        : PrefModule(catEditing, N_("Shortcuts"), form),
-         editItem_(0), mathItem_(0), bufferItem_(0), layoutItem_(0),
-         systemItem_(0)
+         editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
+         systemItem_(nullptr)
 {
        setupUi(this);
 
@@ -2885,8 +2976,8 @@ void PrefShortcuts::applyRC(LyXRC & rc) const
        // The good thing is that the menus are updated automatically.
        theTopLevelKeymap().clear();
        theTopLevelKeymap().read("site");
-       theTopLevelKeymap().read(rc.bind_file, 0, KeyMap::Fallback);
-       theTopLevelKeymap().read("user", 0, KeyMap::MissingOK);
+       theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
+       theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
 }
 
 
@@ -3002,14 +3093,14 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
                        + ' ' + lfun.argument());
        QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
 
-       QTreeWidgetItem * newItem = 0;
+       QTreeWidgetItem * newItem = nullptr;
        // for unbind items, try to find an existing item in the system bind list
        if (tag == KeyMap::UserUnbind) {
-               QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(lfun_name,
-                       Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
-               for (int i = 0; i < items.size(); ++i) {
-                       if (items[i]->text(1) == shortcut) {
-                               newItem = items[i];
+               QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
+                       Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
+               for (auto const & item : items) {
+                       if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
+                               newItem = item;
                                break;
                        }
                }
@@ -3017,13 +3108,13 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
                // Such an item is not displayed to avoid confusion (what is
                // unmatched removed?).
                if (!newItem) {
-                       return 0;
+                       return nullptr;
                }
        }
        if (!newItem) {
                switch(lyxaction.getActionType(action)) {
                case LyXAction::Hidden:
-                       return 0;
+                       return nullptr;
                case LyXAction::Edit:
                        newItem = new QTreeWidgetItem(editItem_);
                        break;
@@ -3043,10 +3134,10 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
                        // this should not happen
                        newItem = new QTreeWidgetItem(shortcutsTW);
                }
+               newItem->setText(0, lfun_name);
+               newItem->setText(1, shortcut);
        }
 
-       newItem->setText(0, lfun_name);
-       newItem->setText(1, shortcut);
        // record BindFile representation to recover KeySequence when needed.
        newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
        setItemType(newItem, tag);
@@ -3096,8 +3187,7 @@ void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
        // list of items that match lfun
        QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
             Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
-       for (int i = 0; i < items.size(); ++i) {
-               QTreeWidgetItem * item = items[i];
+       for (auto const & item : items) {
                if (isAlwaysHidden(*item)) {
                        setItemType(item, KeyMap::System);
                        if (select)
@@ -3113,24 +3203,24 @@ void PrefShortcuts::removeShortcut()
        // it seems that only one item can be selected, but I am
        // removing all selected items anyway.
        QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
-       for (int i = 0; i < items.size(); ++i) {
-               string shortcut = fromqstr(items[i]->data(1, Qt::UserRole).toString());
-               string lfun = fromqstr(items[i]->text(0));
-               FuncRequest func = lyxaction.lookupFunc(lfun);
+       for (auto & item : items) {
+               string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
+               string lfun = fromqstr(item->text(0));
+               FuncRequest const func = lyxaction.lookupFunc(lfun);
 
-               switch (itemType(*items[i])) {
+               switch (itemType(*item)) {
                case KeyMap::System: {
                        // for system bind, we do not touch the item
                        // but add an user unbind item
                        user_unbind_.bind(shortcut, func);
-                       setItemType(items[i], KeyMap::UserUnbind);
+                       setItemType(item, KeyMap::UserUnbind);
                        removePB->setText(qt_("Res&tore"));
                        break;
                }
                case KeyMap::UserBind: {
                        // for user_bind, we remove this bind
-                       QTreeWidgetItem * parent = items[i]->parent();
-                       int itemIdx = parent->indexOfChild(items[i]);
+                       QTreeWidgetItem * parent = item->parent();
+                       int itemIdx = parent->indexOfChild(item);
                        parent->takeChild(itemIdx);
                        if (itemIdx > 0)
                                shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
@@ -3139,7 +3229,7 @@ void PrefShortcuts::removeShortcut()
                        user_bind_.unbind(shortcut, func);
                        // If this user binding hid an empty system binding, unhide the
                        // latter and select it.
-                       unhideEmpty(items[i]->text(0), true);
+                       unhideEmpty(item->text(0), true);
                        break;
                }
                case KeyMap::UserUnbind: {
@@ -3151,15 +3241,15 @@ void PrefShortcuts::removeShortcut()
                        if (!validateNewShortcut(func, seq, QString()))
                                break;
                        user_unbind_.unbind(shortcut, func);
-                       setItemType(items[i], KeyMap::System);
+                       setItemType(item, KeyMap::System);
                        removePB->setText(qt_("Remo&ve"));
                        break;
                }
                case KeyMap::UserExtraUnbind: {
                        // for user unbind that is not in system bind file,
                        // remove this unbind file
-                       QTreeWidgetItem * parent = items[i]->parent();
-                       parent->takeChild(parent->indexOfChild(items[i]));
+                       QTreeWidgetItem * parent = item->parent();
+                       parent->takeChild(parent->indexOfChild(item));
                        user_unbind_.unbind(shortcut, func);
                }
                }
@@ -3169,26 +3259,26 @@ void PrefShortcuts::removeShortcut()
 
 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
 {
-       for (int i = 0; i < items.size(); ++i) {
-               string shortcut = fromqstr(items[i]->data(1, Qt::UserRole).toString());
-               string lfun = fromqstr(items[i]->text(0));
-               FuncRequest func = lyxaction.lookupFunc(lfun);
+       for (auto item : items) {
+               string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
+               string lfun = fromqstr(item->text(0));
+               FuncRequest const func = lyxaction.lookupFunc(lfun);
 
-               switch (itemType(*items[i])) {
+               switch (itemType(*item)) {
                case KeyMap::System:
                        // for system bind, we do not touch the item
                        // but add an user unbind item
                        user_unbind_.bind(shortcut, func);
-                       setItemType(items[i], KeyMap::UserUnbind);
+                       setItemType(item, KeyMap::UserUnbind);
                        break;
 
                case KeyMap::UserBind: {
                        // for user_bind, we remove this bind
-                       QTreeWidgetItem * parent = items[i]->parent();
-                       int itemIdx = parent->indexOfChild(items[i]);
+                       QTreeWidgetItem * parent = item->parent();
+                       int itemIdx = parent->indexOfChild(item);
                        parent->takeChild(itemIdx);
                        user_bind_.unbind(shortcut, func);
-                       unhideEmpty(items[i]->text(0), false);
+                       unhideEmpty(item->text(0), false);
                        break;
                }
                default:
@@ -3238,7 +3328,7 @@ void PrefShortcuts::on_searchLE_textEdited()
                // show all hidden items
                QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
                for (; *it; ++it)
-                       shortcutsTW->setItemHidden(*it, isAlwaysHidden(**it));
+                       (*it)->setHidden(isAlwaysHidden(**it));
                // close all categories
                for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
                        shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
@@ -3253,12 +3343,13 @@ void PrefShortcuts::on_searchLE_textEdited()
        // hide everyone (to avoid searching in matched QList repeatedly
        QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
        while (*it)
-               shortcutsTW->setItemHidden(*it++, true);
+               (*it++)->setHidden(true);
        // show matched items
-       for (int i = 0; i < matched.size(); ++i)
-               if (!isAlwaysHidden(*matched[i])) {
-                       shortcutsTW->setItemHidden(matched[i], false);
-                       shortcutsTW->setItemExpanded(matched[i]->parent(), true);
+       for (auto & item : matched)
+               if (!isAlwaysHidden(*item)) {
+                       item->setHidden(false);
+                       if (item->parent())
+                               item->parent()->setExpanded(true);
                }
 }
 
@@ -3275,9 +3366,10 @@ docstring makeCmdString(FuncRequest const & f)
 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
 {
        FuncRequest res = user_bind_.getBinding(k);
-       if (res.action() != LFUN_UNKNOWN_ACTION)
+       if (res != FuncRequest::unknown)
                return res;
        res = system_bind_.getBinding(k);
+
        // Check if it is unbound. Note: user_unbind_ can only unbind one
        // FuncRequest per key sequence.
        if (user_unbind_.getBinding(k) == res)
@@ -3316,6 +3408,23 @@ bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
                // nothing to change
                return false;
 
+       // Check whether the key sequence is a prefix for other shortcuts.
+       if (oldBinding == FuncRequest::prefix) {
+               docstring const new_action_string = makeCmdString(func);
+               docstring const text = bformat(_("Shortcut `%1$s' is already a prefix for other commands.\n"
+                                                "Are you sure you want to unbind these commands and bind it to %2$s?"),
+                                                                          k.print(KeySequence::ForGui), new_action_string);
+               int ret = Alert::prompt(_("Redefine shortcut?"),
+                                       text, 0, 1, _("&Redefine"), _("&Cancel"));
+               if (ret != 0)
+                       return false;
+               QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
+               QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
+                       Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchRecursive), 1);
+               deactivateShortcuts(items);
+               return true;
+       }
+
        // make sure this key isn't already bound---and, if so, prompt user
        // (exclude the lfun the user already wants to modify)
        docstring const action_string = makeCmdString(oldBinding);
@@ -3344,7 +3453,7 @@ bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
 void PrefShortcuts::shortcutOkPressed()
 {
        QString const new_lfun = shortcut_->lfunLE->text();
-       FuncRequest func = lyxaction.lookupFunc(fromqstr(new_lfun));
+       FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
        KeySequence k = shortcut_->shortcutWG->getKeySequence();
 
        // save_lfun_ contains the text of the lfun to modify, if the user clicked
@@ -3365,7 +3474,8 @@ void PrefShortcuts::shortcutOkPressed()
        if (item) {
                user_bind_.bind(&k, func);
                shortcutsTW->sortItems(0, Qt::AscendingOrder);
-               shortcutsTW->setItemExpanded(item->parent(), true);
+               if (item->parent())
+                       item->parent()->setExpanded(true);
                shortcutsTW->setCurrentItem(item);
                shortcutsTW->scrollToItem(item);
        } else {
@@ -3483,11 +3593,6 @@ GuiPreferences::GuiPreferences(GuiView & lv)
        addModule(formats);
 
        prefsPS->setCurrentPanel("User Interface");
-// FIXME: hack to work around resizing bug in Qt >= 4.2
-// bug verified with Qt 4.2.{0-3} (JSpitzm)
-#if QT_VERSION >= 0x040200
-       prefsPS->updateGeometry();
-#endif
 
        bc().setPolicy(ButtonPolicy::PreferencesPolicy);
        bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
@@ -3657,9 +3762,6 @@ QString GuiPreferences::browse(QString const & file,
 }
 
 
-Dialog * createGuiPreferences(GuiView & lv) { return new GuiPreferences(lv); }
-
-
 } // namespace frontend
 } // namespace lyx