File indexing completed on 2024-04-28 15:14:03

0001 /***************************************************************************
0002     File                 : TemplateHandler.cpp
0003     Project              : LabPlot
0004     Description          : Widget for handling saving and loading of templates
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2012 by Stefan Gerlach (stefan.gerlach@uni.kn)
0007     Copyright            : (C) 2012-2020 by Alexander Semke (alexander.semke@web.de)
0008 
0009  ***************************************************************************/
0010 
0011 /***************************************************************************
0012  *                                                                         *
0013  *  This program is free software; you can redistribute it and/or modify   *
0014  *  it under the terms of the GNU General Public License as published by   *
0015  *  the Free Software Foundation; either version 2 of the License, or      *
0016  *  (at your option) any later version.                                    *
0017  *                                                                         *
0018  *  This program is distributed in the hope that it will be useful,        *
0019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0021  *  GNU General Public License for more details.                           *
0022  *                                                                         *
0023  *   You should have received a copy of the GNU General Public License     *
0024  *   along with this program; if not, write to the Free Software           *
0025  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0026  *   Boston, MA  02110-1301  USA                                           *
0027  *                                                                         *
0028  ***************************************************************************/
0029 
0030 #include "TemplateHandler.h"
0031 
0032 #include <QFileInfo>
0033 #include <QDir>
0034 #include <QHBoxLayout>
0035 #include <QLabel>
0036 #include <QLineEdit>
0037 #include <QMenu>
0038 #include <QSpacerItem>
0039 #include <QToolButton>
0040 #include <QWidgetAction>
0041 
0042 
0043 #include <QApplication>
0044 #include <QMouseEvent>
0045 #include <QTimer>
0046 
0047 #include <KConfig>
0048 #include <KConfigGroup>
0049 #include <KIconLoader>
0050 #include <KLocalizedString>
0051 
0052 static QVector<TemplateHandler*> templateHandlers;
0053 
0054  /*!
0055   \class TemplateHandler
0056   \brief Provides a widget with buttons for saving and loading of templates.
0057 
0058   Emits \c loadConfig() and \c saveConfig() signals that have to be connected
0059   to the appropriate slots in the ui (mostly in the dock widgets)
0060 
0061   \ingroup kdefrontend
0062 */
0063 
0064 TemplateHandler::TemplateHandler(QWidget* parent, ClassName name) : QWidget(parent) {
0065     auto* horizontalLayout = new QHBoxLayout(this);
0066     horizontalLayout->setSpacing(0);
0067     horizontalLayout->setMargin(0);
0068 
0069     auto* horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0070     horizontalLayout->addItem(horizontalSpacer);
0071 
0072     int size = KIconLoader::global()->currentSize(KIconLoader::MainToolbar);
0073 
0074     m_tbLoad = new QToolButton(this);
0075     m_tbLoad->setIconSize(QSize(size, size));
0076     horizontalLayout->addWidget(m_tbLoad);
0077 
0078     m_tbSave = new QToolButton(this);
0079     m_tbSave->setIconSize(QSize(size, size));
0080     horizontalLayout->addWidget(m_tbSave);
0081 
0082     m_tbSaveDefault = new QToolButton(this);
0083     m_tbSaveDefault->setIconSize(QSize(size, size));
0084     horizontalLayout->addWidget(m_tbSaveDefault);
0085 
0086 //  QSpacerItem* horizontalSpacer2 = new QSpacerItem(10, 20, QSizePolicy::Fixed, QSizePolicy::Minimum);
0087 //  horizontalLayout->addItem(horizontalSpacer2);
0088 
0089 //  m_tbCopy = new QToolButton(this);
0090 //  m_tbCopy->setIconSize(QSize(size, size));
0091 //  m_tbCopy->setEnabled(false);
0092 //  horizontalLayout->addWidget(m_tbCopy);
0093 //
0094 //  m_tbPaste = new QToolButton(this);
0095 //  m_tbPaste->setIconSize(QSize(size, size));
0096 //  m_tbPaste->setEnabled(false);
0097 //  horizontalLayout->addWidget(m_tbPaste);
0098 
0099     m_tbLoad->setIcon(QIcon::fromTheme("document-open"));
0100     m_tbSave->setIcon(QIcon::fromTheme("document-save"));
0101     m_tbSaveDefault->setIcon(QIcon::fromTheme("document-save-as"));
0102 //  m_tbCopy->setIcon(QIcon::fromTheme("edit-copy"));
0103 //  m_tbPaste->setIcon(QIcon::fromTheme("edit-paste"));
0104 
0105     connect(m_tbLoad, &QToolButton::clicked, this, &TemplateHandler::loadMenu);
0106     connect(m_tbSave, &QToolButton::clicked, this, &TemplateHandler::saveMenu);
0107     connect(m_tbSaveDefault, &QToolButton::clicked, this, &TemplateHandler::saveDefaults);
0108 
0109 
0110     KConfig config;
0111     KConfigGroup group = config.group(QLatin1String("TemplateHandler"));
0112     auto style = (Qt::ToolButtonStyle)group.readEntry(QLatin1String("TextPosition"), (int)Qt::ToolButtonTextBesideIcon);
0113     m_tbLoad->setToolButtonStyle(style);
0114     m_tbSave->setToolButtonStyle(style);
0115     m_tbSaveDefault->setToolButtonStyle(style);
0116 
0117     m_tbLoad->installEventFilter(this);
0118     m_tbSave->installEventFilter(this);
0119     m_tbSaveDefault->installEventFilter(this);
0120 
0121     m_className = name;
0122 
0123     //folder where config files will be stored in object specific sub-folders:
0124     //Linux    - ~/.local/share/labplot2/templates/
0125     //Mac      - //TODO
0126     //Windows  - C:/Users/<USER>/AppData/Roaming/labplot2/templates/
0127     m_dirName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1String("/templates/");
0128 
0129     //synchronize this with the ordering in TemplateHandler::ClassName
0130     enum ClassName {Spreadsheet, Matrix, Worksheet, CartesianPlot, CartesianPlotLegend, Histogram, XYCurve, Axis, CustomPoint};
0131     m_subDirNames <<"spreadsheet"<<"matrix"<<"worksheet"<<"cartesianplot"
0132                 <<"cartesianplotlegend"<<"histogram"<<"xycurve"<<"axis"<<"custompoint";
0133 
0134     this->retranslateUi();
0135 
0136     //disable the load-button if no templates are available yet
0137     QStringList list = QDir(m_dirName + m_subDirNames.at(static_cast<int>(m_className))).entryList();
0138     list.removeAll(QLatin1String("."));
0139     list.removeAll(QLatin1String(".."));
0140     m_tbLoad->setEnabled(list.size());
0141 
0142     //TODO: implement copy&paste of properties and activate copy- and paste-buttons again
0143 //  m_tbCopy->hide();
0144 //  m_tbPaste->hide();
0145 
0146     templateHandlers << this;
0147 }
0148 
0149 void TemplateHandler::retranslateUi() {
0150     m_tbLoad->setText(i18n("Load"));
0151     m_tbLoad->setToolTip(i18n("Load properties from a template"));
0152     m_tbSave->setText(i18n("Save"));
0153     m_tbSave->setToolTip(i18n("Save current properties as a template"));
0154     m_tbSaveDefault->setText(i18n("Save Default"));
0155     m_tbSaveDefault->setToolTip(i18n("Save current properties as default"));
0156 //  m_tbCopy->setToolTip(i18n("Copy properties"));
0157 //  m_tbPaste->setToolTip(i18n("Paste properties"));
0158 }
0159 
0160 bool TemplateHandler::eventFilter(QObject* obj, QEvent* event) {
0161     if (event->type() == QEvent::MouseButtonPress) {
0162         auto* mouseEvent = static_cast<QMouseEvent*>(event);
0163         if (mouseEvent->button() == Qt::RightButton) {
0164             if (!m_textPositionMenu) {
0165                 auto style = m_tbLoad->toolButtonStyle();
0166 
0167                 m_textPositionMenu = new QMenu(this);
0168                 m_textPositionMenu->addSection(i18n("Toolbar Settings"));
0169 
0170                 auto* actionGroup = new QActionGroup(this);
0171                 actionGroup->setExclusive(true);
0172                 connect(actionGroup, &QActionGroup::triggered, this, &TemplateHandler::updateTextPosition);
0173 
0174                 auto* subMenu = new QMenu(i18n("Text position"), m_textPositionMenu);
0175 
0176                 QAction* action = new QAction(i18n("Icons only"), actionGroup);
0177                 action->setCheckable(true);
0178                 action->setData((int)Qt::ToolButtonIconOnly);
0179                 if (style == Qt::ToolButtonIconOnly)
0180                     action->setChecked(true);
0181                 subMenu->addAction(action);
0182 
0183                 action = new QAction(i18n("Text only"), actionGroup);
0184                 action->setCheckable(true);
0185                 action->setData((int)Qt::ToolButtonTextOnly);
0186                 if (style == Qt::ToolButtonTextOnly)
0187                     action->setChecked(true);
0188                 subMenu->addAction(action);
0189 
0190                 action = new QAction(i18n("Text Alongside Icons"), actionGroup);
0191                 action->setCheckable(true);
0192                 action->setData((int)Qt::ToolButtonTextBesideIcon);
0193                 if (style == Qt::ToolButtonTextBesideIcon)
0194                     action->setChecked(true);
0195                 subMenu->addAction(action);
0196 
0197                 action = new QAction(i18n("Text Under Icons"), actionGroup);
0198                 action->setCheckable(true);
0199                 action->setData((int)Qt::ToolButtonTextUnderIcon);
0200                 if (style == Qt::ToolButtonTextUnderIcon)
0201                     action->setChecked(true);
0202                 subMenu->addAction(action);
0203                 m_textPositionMenu->addMenu(subMenu);
0204 
0205             }
0206 
0207             auto* widget = static_cast<QWidget*>(obj);
0208             m_textPositionMenu->exec(widget->mapToGlobal(mouseEvent->pos()));
0209         }
0210     }
0211     return QWidget::eventFilter(obj, event);
0212 }
0213 
0214 void TemplateHandler::updateTextPosition(QAction* action) {
0215     auto style = static_cast<Qt::ToolButtonStyle>(action->data().toInt());
0216 
0217     //save the current style
0218     KConfig config;
0219     KConfigGroup group = config.group(QLatin1String("TemplateHandler"));
0220     group.writeEntry(QLatin1String("TextPosition"), (int)style);
0221 
0222     //update all available template handlers
0223     for (auto* handler : templateHandlers)
0224         handler->setToolButtonStyle(style);
0225 }
0226 
0227 void TemplateHandler::setToolButtonStyle(Qt::ToolButtonStyle style) {
0228     m_tbLoad->setToolButtonStyle(style);
0229     m_tbSave->setToolButtonStyle(style);
0230     m_tbSaveDefault->setToolButtonStyle(style);
0231 }
0232 
0233 //##############################################################################
0234 //##################################  Slots ####################################
0235 //##############################################################################
0236 void TemplateHandler::loadMenu() {
0237     QMenu menu;
0238     menu.addSection(i18n("Load From Template"));
0239 
0240     QStringList list = QDir(m_dirName + m_subDirNames.at(static_cast<int>(m_className))).entryList();
0241     list.removeAll(QLatin1String("."));
0242     list.removeAll(QLatin1String(".."));
0243     for (int i = 0; i < list.size(); ++i) {
0244         QFileInfo fileinfo(list.at(i));
0245         QAction* action = menu.addAction(QIcon::fromTheme(QLatin1String("document-edit")), fileinfo.fileName());
0246         action->setData(fileinfo.fileName());
0247     }
0248     connect(&menu, &QMenu::triggered, this, &TemplateHandler::loadMenuSelected);
0249 
0250     QPoint pos(-menu.sizeHint().width()+m_tbLoad->width(),-menu.sizeHint().height());
0251     menu.exec(m_tbLoad->mapToGlobal(pos));
0252 }
0253 
0254 void TemplateHandler::loadMenuSelected(QAction* action) {
0255     QString configFile = m_dirName + m_subDirNames.at(static_cast<int>(m_className)) + '/' + action->data().toString();
0256     KConfig config(configFile, KConfig::SimpleConfig);
0257     emit loadConfigRequested(config);
0258     emit info( i18n("Template \"%1\" was loaded.", action->text().remove('&')) );
0259 }
0260 
0261 void TemplateHandler::saveMenu() {
0262     QMenu menu;
0263     menu.addSection(i18n("Save As Template"));
0264 
0265     QStringList list = QDir(m_dirName + m_subDirNames.at(static_cast<int>(m_className))).entryList();
0266     list.removeAll(QLatin1String("."));
0267     list.removeAll(QLatin1String(".."));
0268     for (int i = 0; i < list.size(); ++i) {
0269             QFileInfo fileinfo(list.at(i));
0270             QAction* action = menu.addAction(QIcon::fromTheme(QLatin1String("document-edit")), fileinfo.fileName());
0271             menu.addAction(action);
0272             action->setShortcut(QKeySequence());
0273     }
0274     connect(&menu, &QMenu::triggered, this, &TemplateHandler::saveMenuSelected);
0275 
0276     // add editable action
0277     auto* widgetAction = new QWidgetAction(this);
0278     auto* frame = new QFrame(this);
0279     auto* layout = new QHBoxLayout(frame);
0280 
0281     QLabel* label = new QLabel(i18n("New:"), frame);
0282     layout->addWidget(label);
0283 
0284     QLineEdit* leFilename = new QLineEdit(QString(), frame);
0285     layout->addWidget(leFilename);
0286     connect(leFilename, &QLineEdit::returnPressed, this, [=]() {saveNewSelected(leFilename->text());} );
0287     connect(leFilename, &QLineEdit::returnPressed, &menu, &QMenu::close);
0288 
0289     widgetAction->setDefaultWidget(frame);
0290     if (menu.actions().size() > 1)
0291         menu.addSeparator();
0292     menu.addAction(widgetAction);
0293     leFilename->setFocus();
0294 
0295     QPoint pos(-menu.sizeHint().width()+m_tbSave->width(),-menu.sizeHint().height());
0296     menu.exec(m_tbSave->mapToGlobal(pos));
0297 }
0298 
0299 /*!
0300  * Is called when the current properties are going to be saved as a new template.
0301  * Emits \c saveConfigRequested, the receiver of the signal has to config.sync().
0302  */
0303 void TemplateHandler::saveNewSelected(const QString& filename) {
0304     QString path = m_dirName + m_subDirNames.at(static_cast<int>(m_className)) + '/' + filename;
0305     KConfig config(path, KConfig::SimpleConfig);
0306     emit saveConfigRequested(config);
0307     emit info( i18n("New template \"%1\" was saved.", filename) );
0308 
0309     //we have at least one saved template now -> enable the load button
0310     m_tbLoad->setEnabled(true);
0311 }
0312 
0313 /*!
0314  * Is called when the current properties are going to be saved in an already available template.
0315  * Emits \c saveConfigRequested, the receiver of the signal has to config.sync().
0316  */
0317 void TemplateHandler::saveMenuSelected(QAction* action) {
0318     KConfig config(action->data().toString()+'/'+action->text(), KConfig::SimpleConfig);
0319     emit saveConfigRequested(config);
0320     emit info( i18n("Template \"%1\" was saved.", action->text()) );
0321 }
0322 
0323 /*!
0324  * Is called when the current properties are going to be saved as new default properties.
0325  * Emits \c saveConfigRequested, the receiver of the signal has to config.sync().
0326  */
0327 void TemplateHandler::saveDefaults() {
0328     KConfig config;
0329     emit saveConfigRequested(config);
0330     emit info( i18n("New default template was saved.") );
0331 }