File indexing completed on 2024-05-05 17:43:52

0001 /*
0002     SPDX-FileCopyrightText: 2018 Kai Uwe Broulik <kde@privat.broulik.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "icons.h"
0008 
0009 #include <QHash>
0010 #include <QRegularExpression>
0011 
0012 QString Icons::actionIcon(const QString &actionName)
0013 {
0014     QString icon;
0015 
0016     QString action = actionName;
0017 
0018     if (action.isEmpty()) {
0019         return icon;
0020     }
0021 
0022     static const QHash<QString, QString> s_icons{
0023         {QStringLiteral("new"), QStringLiteral("document-new")}, // appmenu-gtk-module "New"
0024         {QStringLiteral("image-new"), QStringLiteral("document-new")}, // Gimp "New" item
0025         {QStringLiteral("adddirect"), QStringLiteral("document-new")}, // LibreOffice "New" item
0026         {QStringLiteral("filenew"), QStringLiteral("document-new")}, // Pluma "New" item
0027         {QStringLiteral("new-window"), QStringLiteral("window-new")},
0028         {QStringLiteral("newwindow"), QStringLiteral("window-new")},
0029         {QStringLiteral("yelp-window-new"), QStringLiteral("window-new")}, // Gnome help
0030         {QStringLiteral("new-tab"), QStringLiteral("tab-new")},
0031         {QStringLiteral("open"), QStringLiteral("document-open")},
0032         {QStringLiteral("open-location"), QStringLiteral("document-open-remote")},
0033         {QStringLiteral("openremote"), QStringLiteral("document-open-remote")},
0034         {QStringLiteral("save"), QStringLiteral("document-save")},
0035         {QStringLiteral("save-as"), QStringLiteral("document-save-as")},
0036         {QStringLiteral("saveas"), QStringLiteral("document-save-as")},
0037         {QStringLiteral("save-all"), QStringLiteral("document-save-all")},
0038         {QStringLiteral("saveall"), QStringLiteral("document-save-all")},
0039         {QStringLiteral("import"), QStringLiteral("document-import")},
0040         {QStringLiteral("export"), QStringLiteral("document-export")},
0041         {QStringLiteral("exportto"), QStringLiteral("document-export")}, // LibreOffice
0042         {QStringLiteral("exporttopdf"), QStringLiteral("viewpdf")}, // LibreOffice, the icon it uses but the name is quite random
0043         {QStringLiteral("webhtml"), QStringLiteral("text-html")}, // LibreOffice
0044         {QStringLiteral("printpreview"), QStringLiteral("document-print-preview")},
0045         {QStringLiteral("print-preview"), QStringLiteral("document-print-preview")},
0046         {QStringLiteral("print"), QStringLiteral("document-print")},
0047         {QStringLiteral("print-gtk"), QStringLiteral("document-print")}, // Gimp
0048         {QStringLiteral("mail-image"), QStringLiteral("mail-message-new")}, // Gimp
0049         {QStringLiteral("sendmail"), QStringLiteral("mail-message-new")}, // LibreOffice
0050         {QStringLiteral("sendviabluetooth"), QStringLiteral("preferences-system-bluetooth")}, // LibreOffice
0051         {QStringLiteral("sendviabluetooth"), QStringLiteral("preferences-system-bluetooth")}, // LibreOffice
0052         {QStringLiteral("document-properties"), QStringLiteral("document-properties")},
0053         {QStringLiteral("close"), QStringLiteral("document-close")}, // appmenu-gtk-module "Close"
0054         {QStringLiteral("closedoc"), QStringLiteral("document-close")},
0055         {QStringLiteral("close-all"), QStringLiteral("document-close")},
0056         {QStringLiteral("closeall"), QStringLiteral("document-close")},
0057         {QStringLiteral("closewin"), QStringLiteral("window-close")}, // LibreOffice
0058         {QStringLiteral("quit"), QStringLiteral("application-exit")},
0059 
0060         {QStringLiteral("undo"), QStringLiteral("edit-undo")},
0061         {QStringLiteral("redo"), QStringLiteral("edit-redo")},
0062         {QStringLiteral("revert"), QStringLiteral("document-revert")},
0063         {QStringLiteral("cut"), QStringLiteral("edit-cut")},
0064         {QStringLiteral("copy"), QStringLiteral("edit-copy")},
0065         {QStringLiteral("paste"), QStringLiteral("edit-paste")},
0066         {QStringLiteral("duplicate"), QStringLiteral("edit-duplicate")},
0067 
0068         {QStringLiteral("preferences"), QStringLiteral("settings-configure")},
0069         {QStringLiteral("optionstreedialog"), QStringLiteral("settings-configure")}, // LibreOffice
0070         {QStringLiteral("keyboard-shortcuts"), QStringLiteral("configure-shortcuts")},
0071 
0072         {QStringLiteral("fullscreen"), QStringLiteral("view-fullscreen")},
0073 
0074         {QStringLiteral("find"), QStringLiteral("edit-find")},
0075         {QStringLiteral("searchfind"), QStringLiteral("edit-find")},
0076         {QStringLiteral("replace"), QStringLiteral("edit-find-replace")},
0077         {QStringLiteral("searchreplace"), QStringLiteral("edit-find-replace")}, // LibreOffice
0078         {QStringLiteral("searchdialog"), QStringLiteral("edit-find-replace")}, // LibreOffice
0079         {QStringLiteral("find-replace"), QStringLiteral("edit-find-replace")}, // Inkscape
0080         {QStringLiteral("select-all"), QStringLiteral("edit-select-all")},
0081         {QStringLiteral("selectall"), QStringLiteral("edit-select-all")},
0082         {QStringLiteral("select-none"), QStringLiteral("edit-select-invert")},
0083         {QStringLiteral("select-invert"), QStringLiteral("edit-select-invert")},
0084         {QStringLiteral("invert-selection"), QStringLiteral("edit-select-invert")}, // Inkscape
0085         {QStringLiteral("check-spelling"), QStringLiteral("tools-check-spelling")},
0086         {QStringLiteral("set-language"), QStringLiteral("set-language")},
0087 
0088         {QStringLiteral("increasesize"), QStringLiteral("zoom-in")},
0089         {QStringLiteral("decreasesize"), QStringLiteral("zoom-out")},
0090         {QStringLiteral("zoom-in"), QStringLiteral("zoom-in")},
0091         {QStringLiteral("zoom-out"), QStringLiteral("zoom-out")},
0092         {QStringLiteral("zoomfit"), QStringLiteral("zoom-fit-best")},
0093         {QStringLiteral("zoom-fit-in"), QStringLiteral("zoom-fit-best")},
0094         {QStringLiteral("show-guides"), QStringLiteral("show-guides")},
0095         {QStringLiteral("show-grid"), QStringLiteral("show-grid")},
0096 
0097         {QStringLiteral("rotateclockwise"), QStringLiteral("object-rotate-right")},
0098         {QStringLiteral("rotatecounterclockwise"), QStringLiteral("object-rotate-left")},
0099         {QStringLiteral("fliphorizontally"), QStringLiteral("object-flip-horizontal")},
0100         {QStringLiteral("image-flip-horizontal"), QStringLiteral("object-flip-horizontal")},
0101         {QStringLiteral("flipvertically"), QStringLiteral("object-flip-vertical")},
0102         {QStringLiteral("image-flip-vertical"), QStringLiteral("object-flip-vertical")},
0103         {QStringLiteral("image-scale"), QStringLiteral("transform-scale")},
0104 
0105         {QStringLiteral("bold"), QStringLiteral("format-text-bold")},
0106         {QStringLiteral("italic"), QStringLiteral("format-text-italic")},
0107         {QStringLiteral("underline"), QStringLiteral("format-text-underline")},
0108         {QStringLiteral("strikeout"), QStringLiteral("format-text-strikethrough")},
0109         {QStringLiteral("superscript"), QStringLiteral("format-text-superscript")},
0110         {QStringLiteral("subscript"), QStringLiteral("format-text-subscript")},
0111         // "grow" is a bit unspecific to always set it to "grow font", so use the exact ID here
0112         {QStringLiteral(".uno:Grow"), QStringLiteral("format-font-size-more")}, // LibreOffice
0113         {QStringLiteral(".uno:Shrink"), QStringLiteral("format-font-size-less")}, // LibreOffice
0114         // also a bit unspecific?
0115         {QStringLiteral("alignleft"), QStringLiteral("format-justify-left")},
0116         {QStringLiteral("alignhorizontalcenter"), QStringLiteral("format-justify-center")},
0117         {QStringLiteral("alignright"), QStringLiteral("format-justify-right")},
0118         {QStringLiteral("alignjustified"), QStringLiteral("format-justify-fill")},
0119         {QStringLiteral("incrementindent"), QStringLiteral("format-indent-more")},
0120         {QStringLiteral("decrementindent"), QStringLiteral("format-indent-less")},
0121         {QStringLiteral("defaultbullet"), QStringLiteral("format-list-unordered")}, // LibreOffice
0122         {QStringLiteral("defaultnumbering"), QStringLiteral("format-list-ordered")}, // LibreOffice
0123 
0124         {QStringLiteral("sortascending"), QStringLiteral("view-sort-ascending")},
0125         {QStringLiteral("sortdescending"), QStringLiteral("view-sort-descending")},
0126 
0127         {QStringLiteral("autopilotmenu"), QStringLiteral("tools-wizard")}, // LibreOffice
0128 
0129         {QStringLiteral("layers-new"), QStringLiteral("layer-new")},
0130         {QStringLiteral("layers-duplicate"), QStringLiteral("layer-duplicate")},
0131         {QStringLiteral("layers-delete"), QStringLiteral("layer-delete")},
0132         {QStringLiteral("layers-anchor"), QStringLiteral("anchor")},
0133 
0134         {QStringLiteral("slideshow"), QStringLiteral("media-playback-start")}, // Gwenview uses this icon for that
0135         {QStringLiteral("playvideo"), QStringLiteral("media-playback-start")},
0136 
0137         {QStringLiteral("addtags"), QStringLiteral("tag-new")},
0138         {QStringLiteral("newevent"), QStringLiteral("appointment-new")},
0139 
0140         {QStringLiteral("previous-document"), QStringLiteral("go-previous")},
0141         {QStringLiteral("prevphoto"), QStringLiteral("go-previous")},
0142         {QStringLiteral("next-document"), QStringLiteral("go-next")},
0143         {QStringLiteral("nextphoto"), QStringLiteral("go-next")},
0144 
0145         {QStringLiteral("redeye"), QStringLiteral("redeyes")},
0146         {QStringLiteral("crop"), QStringLiteral("transform-crop")},
0147         {QStringLiteral("move"), QStringLiteral("transform-move")},
0148         {QStringLiteral("rotate"), QStringLiteral("transform-rotate")},
0149         {QStringLiteral("scale"), QStringLiteral("transform-scale")},
0150         {QStringLiteral("shear"), QStringLiteral("transform-shear")},
0151         {QStringLiteral("flip"), QStringLiteral("object-flip-horizontal")},
0152         {QStringLiteral("flag"), QStringLiteral("flag-red")}, // is there a "mark" or "important" icon that isn't email?
0153 
0154         {QStringLiteral("tools-measure"), QStringLiteral("measure")},
0155         {QStringLiteral("tools-text"), QStringLiteral("draw-text")},
0156         {QStringLiteral("tools-color-picker"), QStringLiteral("color-picker")},
0157         {QStringLiteral("tools-paintbrush"), QStringLiteral("draw-brush")},
0158         {QStringLiteral("tools-eraser"), QStringLiteral("draw-eraser")},
0159         {QStringLiteral("tools-paintbrush"), QStringLiteral("draw-brush")},
0160 
0161         {QStringLiteral("help"), QStringLiteral("help-contents")},
0162         {QStringLiteral("helpindex"), QStringLiteral("help-contents")},
0163         {QStringLiteral("contents"), QStringLiteral("help-contents")},
0164         {QStringLiteral("helpcontents"), QStringLiteral("help-contents")},
0165         {QStringLiteral("context-help"), QStringLiteral("help-whatsthis")},
0166         {QStringLiteral("extendedhelp"), QStringLiteral("help-whatsthis")}, // LibreOffice
0167         {QStringLiteral("helpreportproblem"), QStringLiteral("tools-report-bug")},
0168         {QStringLiteral("sendfeedback"), QStringLiteral("tools-report-bug")}, // LibreOffice
0169         {QStringLiteral("about"), QStringLiteral("help-about")},
0170 
0171         {QStringLiteral("emptytrash"), QStringLiteral("trash-empty")},
0172         {QStringLiteral("movetotrash"), QStringLiteral("user-trash-symbolic")},
0173 
0174         // Gnome help
0175         {QStringLiteral("yelp-application-larger-text"), QStringLiteral("format-font-size-more")},
0176         {QStringLiteral("yelp-application-smaller-text"), QStringLiteral("format-font-size-less")}, // LibreOffice
0177 
0178         // LibreOffice documents in its New menu
0179         {QStringLiteral("private:factory/swriter"), QStringLiteral("application-vnd.oasis.opendocument.text")},
0180         {QStringLiteral("private:factory/scalc"), QStringLiteral("application-vnd.oasis.opendocument.spreadsheet")},
0181         {QStringLiteral("private:factory/simpress"), QStringLiteral("application-vnd.oasis.opendocument.presentation")},
0182         {QStringLiteral("private:factory/sdraw"), QStringLiteral("application-vnd.oasis.opendocument.graphics")},
0183         {QStringLiteral("private:factory/swriter/web"), QStringLiteral("text-html")},
0184         {QStringLiteral("private:factory/smath"), QStringLiteral("application-vnd.oasis.opendocument.formula")},
0185     };
0186 
0187     // Sometimes we get additional arguments (?slot=123) we don't care about
0188     const int questionMarkIndex = action.indexOf(QLatin1Char('?'));
0189     if (questionMarkIndex > -1) {
0190         action.truncate(questionMarkIndex);
0191     }
0192 
0193     icon = s_icons.value(action);
0194 
0195     if (icon.isEmpty()) {
0196         const int dotIndex = action.indexOf(QLatin1Char('.')); // app., win., or unity. prefix
0197 
0198         QString prefix;
0199         if (dotIndex > -1) {
0200             prefix = action.left(dotIndex);
0201 
0202             action = action.mid(dotIndex + 1);
0203         }
0204 
0205         // appmenu-gtk-module
0206         if (prefix == QLatin1String("unity")) {
0207             // Remove superfluous hyphens added by appmenu-gtk-module
0208             // First remove multiple subsequent ones
0209             static QRegularExpression subsequentHyphenRegExp(QStringLiteral("-{2,}"));
0210             action.replace(subsequentHyphenRegExp, QStringLiteral("-"));
0211 
0212             // now we can be sure we only have a single hyphen at the start or end, remove it if needed
0213             if (action.startsWith(QLatin1Char('-'))) {
0214                 action.remove(0, 1);
0215             }
0216             if (action.endsWith(QLatin1Char('-'))) {
0217                 action.chop(1);
0218             }
0219 
0220             // It also turns accelerators (&) into hyphens, so remove any hyphen that comes before
0221             // a lower-case letter ("mid sentence"), e.g. "P-references"
0222             static QRegularExpression strayHyphenRegExp(QStringLiteral("-(?=[a-z]+)"));
0223             action.remove(strayHyphenRegExp);
0224         }
0225 
0226         icon = s_icons.value(action);
0227     }
0228 
0229     if (icon.isEmpty()) {
0230         static const auto s_dup1Prefix = QStringLiteral("dup:1:"); // can it be dup2 also?
0231         if (action.startsWith(s_dup1Prefix)) {
0232             action = action.mid(s_dup1Prefix.length());
0233         }
0234 
0235         static const auto s_unoPrefix = QStringLiteral(".uno:"); // LibreOffice with appmenu-gtk
0236         if (action.startsWith(s_unoPrefix)) {
0237             action = action.mid(s_unoPrefix.length());
0238         }
0239 
0240         // LibreOffice's "Open" entry is always "OpenFromAppname" so we just chop that off
0241         if (action.startsWith(QLatin1String("OpenFrom"))) {
0242             action.truncate(4); // basically "Open"
0243         }
0244 
0245         icon = s_icons.value(action);
0246     }
0247 
0248     if (icon.isEmpty()) {
0249         static const auto s_commonPrefix = QStringLiteral("Common");
0250         if (action.startsWith(s_commonPrefix)) {
0251             action = action.mid(s_commonPrefix.length());
0252         }
0253 
0254         icon = s_icons.value(action);
0255     }
0256 
0257     if (icon.isEmpty()) {
0258         static const auto s_prefixes = QStringList{
0259             // Gimp with appmenu-gtk
0260             QStringLiteral("file-"),
0261             QStringLiteral("edit-"),
0262             QStringLiteral("view-"),
0263             QStringLiteral("image-"),
0264             QStringLiteral("layers-"),
0265             QStringLiteral("colors-"),
0266             QStringLiteral("tools-"),
0267             QStringLiteral("plug-in-"),
0268             QStringLiteral("windows-"),
0269             QStringLiteral("dialogs-"),
0270             QStringLiteral("help-"),
0271         };
0272 
0273         for (const QString &prefix : s_prefixes) {
0274             if (action.startsWith(prefix)) {
0275                 action = action.mid(prefix.length());
0276                 break;
0277             }
0278         }
0279 
0280         icon = s_icons.value(action);
0281     }
0282 
0283     if (icon.isEmpty()) {
0284         action = action.toLower();
0285         icon = s_icons.value(action);
0286     }
0287 
0288     if (icon.isEmpty()) {
0289         static const auto s_prefixes = QStringList{
0290             // Pluma with appmenu-gtk
0291             QStringLiteral("file"),
0292             QStringLiteral("edit"),
0293             QStringLiteral("view"),
0294             QStringLiteral("help"),
0295         };
0296 
0297         for (const QString &prefix : s_prefixes) {
0298             if (action.startsWith(prefix)) {
0299                 action = action.mid(prefix.length());
0300                 break;
0301             }
0302         }
0303 
0304         icon = s_icons.value(action);
0305     }
0306 
0307     return icon;
0308 }