1 /***************************************************************************
2  *   file klfadvancedconfigeditor_p.h
3  *   This file is part of the KLatexFormula Project.
4  *   Copyright (C) 2012 by Philippe Faist
5  *   philippe.faist at bluewin.ch
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22 /* $Id: klfadvancedconfigeditor_p.h 988 2017-01-02 09:25:34Z phfaist $ */
23 
24 /** \file
25  * This header contains (in principle private) auxiliary classes for
26  * library routines defined in klfadvancedconfigeditor.cpp */
27 
28 #ifndef KLFADVANCEDCONFIGEDITOR_P_H
29 #define KLFADVANCEDCONFIGEDITOR_P_H
30 
31 #include <QAbstractItemModel>
32 #include <QStyledItemDelegate>
33 #include <QLineEdit>
34 #include <QStandardItemModel>
35 #include <QMessageBox>
36 #include <QFontDialog>
37 
38 
39 #include <klfdefs.h>
40 #include <klfdatautil.h>
41 
42 #include "klfadvancedconfigeditor.h"
43 #include <ui_klfadvancedconfigeditor.h>
44 
45 
46 #define CONFIG_VIEW_ROLE_PROPNAME	(Qt::UserRole)
47 #define CONFIG_VIEW_ROLE_TYPENAME	(Qt::UserRole+1)
48 #define CONFIG_VIEW_ROLE_INNERTYPENAME	(Qt::UserRole+2)
49 
50 
51 // ---------------------------------------------
52 
53 class KLFAdvancedConfigItemDelegate : public QStyledItemDelegate
54 {
55   Q_OBJECT
56 public:
KLFAdvancedConfigItemDelegate(QObject * parent)57   KLFAdvancedConfigItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
58   {
59   }
60 
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & index)61   virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem& option,
62                                  const QModelIndex& index) const
63   {
64     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
65     if (index.column() < 2)
66       return QStyledItemDelegate::createEditor(parent, option, index);
67     return new QLineEdit(parent);
68   }
69 
setEditorData(QWidget * editor,const QModelIndex & index)70   virtual void setEditorData(QWidget *editor, const QModelIndex& index) const
71   {
72     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
73     klfDbg("editor="<<editor<<", index="<<index) ;
74 
75     if (index.column() < 2)
76       return QStyledItemDelegate::setEditorData(editor, index);
77     // else:
78     QLineEdit * e = qobject_cast<QLineEdit*>(editor);
79     KLF_ASSERT_NOT_NULL(e, "Editor is NULL or not a QLineEdit!", return ; ) ;
80     QVariant value = index.data(Qt::EditRole);
81     klfDbg("value is "<<value) ;
82     e->setText(klfSaveVariantToText(value));
83   }
84 
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index)85   virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const
86   {
87     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
88     klfDbg("editor="<<editor<<", model="<<model<<", index="<<index) ;
89 
90     if (index.column() < 2) {
91       klfDbg("letting base class handle this.") ;
92       return QStyledItemDelegate::setModelData(editor, model, index);
93     }
94     // else:
95     QLineEdit * e = qobject_cast<QLineEdit*>(editor);
96     KLF_ASSERT_NOT_NULL(e, "Editor is NULL or not a QLineEdit!", return ; ) ;
97     KLF_ASSERT_NOT_NULL(model, "Model is NULL!", return ; ) ;
98     QByteArray datavalue = e->text().toLatin1();
99     QByteArray typname = model->data(index, CONFIG_VIEW_ROLE_TYPENAME).toByteArray();
100     QByteArray innertypname = model->data(index, CONFIG_VIEW_ROLE_INNERTYPENAME).toByteArray();
101     QVariant value = klfLoadVariantFromText(datavalue, typname, innertypname);
102     klfDbg("value is "<<value) ;
103     model->setData(index, value, Qt::EditRole);
104   }
105 
106 protected:
107 
editorEvent(QEvent * event,QAbstractItemModel * model,const QStyleOptionViewItem & option,const QModelIndex & index)108   virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem& option,
109 			   const QModelIndex& index)
110   {
111     // Note: editor closes and doesn't apply new value for colors, which open a separate popup
112     // widget... (MAC OS X ONLY)   SOLUTION: use an actual dialog as the widget, this is handled nicely.
113     return QStyledItemDelegate::editorEvent(event, model, option, index);
114   }
115 };
116 
117 
118 // ---------------------------------------------------------------
119 
120 
121 struct KLFAdvancedConfigEditorPrivate : public QObject
122 {
123   Q_OBJECT
124 public:
KLF_PRIVATE_QOBJ_HEADKLFAdvancedConfigEditorPrivate125   KLF_PRIVATE_QOBJ_HEAD(KLFAdvancedConfigEditor, QObject)
126   {
127     pConfigBase = NULL;
128     pCurrentInternalUpdate = false;
129     _are_resetting_config = false;
130   }
131 
132   KLFConfigBase * pConfigBase;
133 
134   bool _are_resetting_config;
135 
136   QStandardItemModel *pConfModel;
137 
138   bool pCurrentInternalUpdate;
139 
140 public slots: // public is just for us... the class is still private :)
141 
configEntryEditedKLFAdvancedConfigEditorPrivate142   void configEntryEdited(QStandardItem *item)
143   {
144     KLF_DEBUG_BLOCK(KLF_FUNC_NAME);
145     klfDbg( "item="<<item<<"" ) ;
146     KLF_ASSERT_NOT_NULL(item, "item is NULL!", return; ) ;
147 
148     if (pCurrentInternalUpdate)
149       return;
150 
151     if (item->column() < 1 || item->column() > 2)
152       return; // false edit
153 
154     klfDbg("config entry edited...");
155 
156     QVariant value = item->data(Qt::EditRole);
157     QString pname = item->data(CONFIG_VIEW_ROLE_PROPNAME).toString();
158     KLFConfigPropBase *p = pConfigBase->property(pname);
159     KLF_ASSERT_NOT_NULL(p, "Property is NULL!", return; ) ;
160     QVariant oldvalue = p->toVariant();
161 
162     if (value == oldvalue) {
163       // never mind, the user didn't change anything.
164       // but still update the row, because otherwise the wrong string representation is shown (why?)
165       updateConfigEntry(item->row());
166       return;
167     }
168 
169     QMessageBox msgBox;
170     msgBox.setText(tr("You are changing an advanced config setting. Please confirm your action."));
171     msgBox.setIcon(QMessageBox::Information);
172     msgBox.setInformativeText(tr("Change config entry %1 from %2 to %3?")
173 			      .arg( "<b>"+pname+"</b>" ,
174 				    "<b>"+klfSaveVariantToText(oldvalue)+"</b> <i>("+oldvalue.typeName()+")</i>" ,
175 				    "<b>"+klfSaveVariantToText(value)+"</b> <i>("+value.typeName()+")</i>"));
176     msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
177     msgBox.setDefaultButton(QMessageBox::Save);
178     int r = msgBox.exec();
179     if (r != QMessageBox::Save) {
180       updateConfigEntry(item->row());
181       return;
182     }
183 
184     r = p->setValue(value);
185     if ( ! r ) {
186       QMessageBox::critical(K, tr("Error"),
187 			    tr("Failed to set config entry `%1'.").arg(pname));
188     }
189     updateConfigEntry(item->row());
190     if (!_are_resetting_config)
191       emit K->configModified(pname);
192   }
193 
194 #define EDITTYPE_TEST_FOR(t, x)  if ((t) == x) { return true; }
is_editable_typeKLFAdvancedConfigEditorPrivate195   static bool is_editable_type(int t)
196   {
197     EDITTYPE_TEST_FOR(t, QVariant::Bool);
198     EDITTYPE_TEST_FOR(t, QVariant::Double);
199     EDITTYPE_TEST_FOR(t, QVariant::Int);
200     EDITTYPE_TEST_FOR(t, QVariant::UInt);
201     EDITTYPE_TEST_FOR(t, QVariant::Date);
202     EDITTYPE_TEST_FOR(t, QVariant::Time);
203     EDITTYPE_TEST_FOR(t, QVariant::DateTime);
204     EDITTYPE_TEST_FOR(t, QVariant::String);
205     EDITTYPE_TEST_FOR(t, QVariant::Color);
206     EDITTYPE_TEST_FOR(t, QVariant::Font);
207     return false;
208   }
209 
updateConfigViewKLFAdvancedConfigEditorPrivate210   void updateConfigView()
211   {
212     pConfModel->setRowCount(0);
213     int k;
214     QStringList props = pConfigBase->propertyList();
215     QPalette pal = K->u->configView->palette();
216     for (k = 0; k < props.size(); ++k) {
217       QString pname = props[k];
218       KLFConfigPropBase *p = pConfigBase->property(pname);
219       QVariant val = p->toVariant();
220       // Config Entry
221       QStandardItem *i1 = new QStandardItem(pname);
222       i1->setEditable(false);
223       // Config Value (edit type directly)
224       QStandardItem *i2 = new QStandardItem(val.toString());
225       bool editable = pConfigBase->okChangeProperty(p, QVariant(), QVariant());
226       bool varianteditable = editable && is_editable_type(val.userType());
227       i2->setEditable(varianteditable);
228       QPalette::ColorGroup cg = varianteditable ? QPalette::Active : QPalette::Disabled;
229       i2->setForeground(pal.brush(cg, QPalette::Text));
230       i2->setBackground(pal.brush(cg, QPalette::Base));
231       //      klfDbg("Adding value: val="<<val<<"; displaystring="<<displayString(val)) ;
232       i2->setData(val, Qt::EditRole);
233       i2->setData(displayString(val), Qt::DisplayRole);
234       i2->setData(pname, CONFIG_VIEW_ROLE_PROPNAME); // user data is property name
235       // Config Value (config text representation)
236       QByteArray savedtype, savedinnertype;
237       QByteArray datavalue = klfSaveVariantToText(val, false, &savedtype, &savedinnertype);
238       klfDbg("i3: datavalue="<<datavalue) ;
239       QStandardItem *i3 = new QStandardItem(QString::fromLatin1(datavalue));
240       cg = editable ? QPalette::Active : QPalette::Disabled;
241       i3->setForeground(pal.brush(cg, QPalette::Text));
242       i3->setBackground(pal.brush(cg, QPalette::Base));
243       i3->setData(val, Qt::EditRole);
244       i3->setData(QString::fromLatin1(datavalue), Qt::DisplayRole);
245       i3->setData(pname, CONFIG_VIEW_ROLE_PROPNAME);
246       i3->setData(savedtype, CONFIG_VIEW_ROLE_TYPENAME);
247       i3->setData(savedinnertype, CONFIG_VIEW_ROLE_INNERTYPENAME);
248       pConfModel->appendRow(QList<QStandardItem*>() << i1 << i2 << i3);
249     }
250   }
updateConfigEntryKLFAdvancedConfigEditorPrivate251   void updateConfigEntry(int row)
252   {
253     pCurrentInternalUpdate = true;
254     QStandardItem *i2 = pConfModel->item(row, 1);
255     QStandardItem *i3 = pConfModel->item(row, 2);
256     QString pname = i2->data(CONFIG_VIEW_ROLE_PROPNAME).toString();
257     KLF_ASSERT_CONDITION(pname == i3->data(CONFIG_VIEW_ROLE_PROPNAME).toString(),
258 			 "BUG?! pnames don't match for both config items",
259 			 return ; );
260     QVariant val = pConfigBase->property(pname)->toVariant();
261     i2->setText(val.toString());
262     i2->setData(val, Qt::EditRole);
263     i2->setData(displayString(val), Qt::DisplayRole);
264     i3->setData(val, Qt::EditRole);
265     i3->setData(klfSaveVariantToText(val), Qt::DisplayRole);
266     pCurrentInternalUpdate = false;
267   }
268 
resetDefaultKLFAdvancedConfigEditorPrivate269   void resetDefault()
270   {
271     QModelIndex index = K->u->configView->currentIndex();
272     if (index == QModelIndex())
273       return;
274     int row = index.row();
275     QStandardItem *i2 = pConfModel->item(row, 1);
276     QStandardItem *i3 = pConfModel->item(row, 2);
277     QString pname = i2->data(CONFIG_VIEW_ROLE_PROPNAME).toString();
278     KLF_ASSERT_CONDITION(pname == i3->data(CONFIG_VIEW_ROLE_PROPNAME).toString(),
279 			 "BUG?! pnames don't match for both config items",
280 			 return ; );
281     KLFConfigPropBase *p = pConfigBase->property(pname);
282     KLF_ASSERT_NOT_NULL(p, "Property is NULL!", return; ) ;
283     QVariant oldvalue = p->toVariant();
284     QVariant defval = p->defaultValueVariant();
285 
286     QMessageBox msgBox;
287     msgBox.setText(tr("You are resetting an advanced config setting to its factory default value. "
288                       "Please confirm your action."));
289     msgBox.setIcon(QMessageBox::Information);
290     msgBox.setInformativeText(tr("Change config entry %1 from %2 to its factory default value %3?")
291 			      .arg( "<b>"+pname+"</b>" ,
292 				    "<b>"+klfSaveVariantToText(oldvalue)+"</b> <i>("+oldvalue.typeName()+")</i>" ,
293 				    "<b>"+klfSaveVariantToText(defval)+"</b> <i>("+defval.typeName()+")</i>"));
294     msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
295     msgBox.setDefaultButton(QMessageBox::Save);
296     int r = msgBox.exec();
297     if (r != QMessageBox::Save) {
298       updateConfigEntry(row);
299       return;
300     }
301 
302     // save the default value
303     r = p->setValue(defval);
304     if ( ! r ) {
305       QMessageBox::critical(K, tr("Error"),
306 			    tr("Failed to set config entry `%1'.").arg(pname));
307     }
308     updateConfigEntry(row);
309   }
310 
311 private:
312   //   QString displayString(QVariant val) {
313   //     if (val.type() == QVariant::Color) {
314   //       QColor c = val.value<QColor>();
315   //       if (c.alpha() == 255)
316   //         return c.name();
317   //       return c.name()+" ("+QString::number(c.alpha()*100/255)+"%)";
318   //     }
319   //     return val.toString();
320   //   }
321 
322   // If a string DisplayRole is set, then the list pops up the wrong editor. (Bug in Qt?)
displayStringKLFAdvancedConfigEditorPrivate323   inline QVariant displayString(QVariant v) {
324     return v;
325   }
326 };
327 
328 
329 
330 
331 // ------------------------
332 
333 
334 class KLFFontDialog : public QFontDialog
335 {
336   Q_OBJECT
337 
338   // just expose this property as the USER property, which is not done in QFontDialog.
339   Q_PROPERTY(QFont theFont READ currentFont WRITE setCurrentFont USER true);
340 public:
341   KLFFontDialog(QWidget *parent = 0)
QFontDialog(parent)342     : QFontDialog(parent)
343   {
344   }
345 
~KLFFontDialog()346   virtual ~KLFFontDialog()
347   {
348   }
349 };
350 
351 
352 #endif
353