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 }