1 /***************************************************************************
2                           rkoptionset  -  description
3                              -------------------
4     begin                : Mon Oct 31 2011
5     copyright            : (C) 2011, 2012 by Thomas Friedrichsmeier
6     email                : thomas.friedrichsmeier@kdemail.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef RKOPTIONSET_H
19 #define RKOPTIONSET_H
20 
21 #include <rkcomponent.h>
22 
23 #include <qmap.h>
24 #include <QDomElement>
25 #include <QTimer>
26 #include <QSet>
27 #include <QAbstractTableModel>
28 
29 class RKAccordionTable;
30 class QTreeView;
31 class QPushButton;
32 class RKOptionSetDisplayModel;
33 class QStackedWidget;
34 
35 /** An RKOptionSet provides a group of options for an arbitrary number of "rows". E.g. different line colors for each of a group of variables.
36  *
37  * @author Thomas Friedrichsmeier
38  */
39 class RKOptionSet : public RKComponent {
40 	Q_OBJECT
41 public:
42 	RKOptionSet (const QDomElement &element, RKComponent *parent_component, QWidget *parent_widget);
43 	~RKOptionSet ();
type()44 	int type () override { return ComponentOptionSet; };
45 	bool isValid () override;
46 	/** reimplemented from RKComponent */
47 	ComponentStatus recursiveStatus () override;
48 	/** reimplemented from RKComponent */
49 	void changed () override;
50 private slots:
51 	void governingPropertyChanged (RKComponentPropertyBase *property);
52 	void columnPropertyChanged (RKComponentPropertyBase *property);
53 	void currentRowPropertyChanged (RKComponentPropertyBase *property);
54 	void serializationPropertyChanged (RKComponentPropertyBase *property);
55 	void addRow (int where);
56 	void removeRow (int which);
57 	void currentRowChanged (int row);
58 	void fetchDefaults ();
59 	void slotUpdateUnfinishedRows ();
60 /** When keys in the key column change, all other columns have to be updated, accordingly. */
61 	void handleKeycolumnUpdate ();
62 protected:
63 friend class RKOptionSetDelegate;
64 	void fetchPropertyValuesRecursive (PropertyValueMap *list, bool include_top_level=false, const QString &prefix=QString (), bool include_inactive_elements=false) const override;
65 friend class RKOptionSetDisplayModel;
rowCount()66 	int rowCount () const { return row_count->intValue (); };
67 	void setRowState (int row, bool finished, bool valid);
68 	void storeRowSerialization (int row);
69 	void applyContentsFromExternalColumn (RKComponentPropertyStringList* column, int row);
70 	void moveRow (int old_index, int new_index);
71 
72 	RKComponentPropertyInt *current_row;
73 	RKComponentPropertyInt *row_count;
74 /** Un-serializing an optionset's state is terribly complicated, if it isn't guaranteed to happen in a single batch. Therefore, we
75  * keep a dedicated property (serialization_of_set), which holds a _full_ serialization of the set's state.
76  * However, this representation is not kept up to date, for performance reasons. Rather it is generated only in fetchPropertyValuesRecursive(). */
77  	RKComponentPropertyBase *serialization_of_set;
78 
79 /** for option sets which are "driven" (i.e. the user cannot simply add / remove rows, directly), this holds the key column, controlling addition / removal of rows in the set.
80   * if this length (or order) is changed in this row, it will also be changed in the other rows. */
81 	RKComponentPropertyStringList *keycolumn;
82 	QStringList old_keys;
83 
84 	/** Map of properties (in the contents region) to columns which need to be updated, when the property changes. */
85 	QMultiMap<RKComponentPropertyBase *, RKComponentPropertyStringList *> columns_to_update;
86 	struct ColumnInfo {
87 		QString column_name;
88 		QString column_label;
89 		QString governor;
90 		QString governor_modifier;
91 		QString default_value;
92 		int display_index;
93 		bool external;
94 	};
95 	/** Map of all columns to their meta info */
96 	QMap<RKComponentPropertyStringList *, ColumnInfo> column_map;
97 	QList<RKComponentPropertyStringList*> visible_columns;
98 	struct RowInfo {
RowInfoRowInfo99 		RowInfo (PropertyValueMap initial_values) : valid (false), finished (false), full_row_map (initial_values) {};
100 		bool valid;		/**< has finished processing and is known to be valid */
101 		bool finished;	/**< has finished processing */
102 		PropertyValueMap full_row_map;	/**< complete status representation of this row, (see RKComponent::fetchPropertyValuesRecursive()) */
103 	};
104 	QList<RowInfo> rows;
105 	PropertyValueMap default_row_state;
106 	int n_unfinished_rows, n_invalid_rows;
107 	int active_row;
108 	/** backup of row state info for rows corresponding to keys which have been removed (in a driven set). These might get re-inserted, later. */
109 	QHash<QString, PropertyValueMap> former_row_states;
110 
111 	RKComponent *contents_container;
112 	ComponentStatus last_known_status;
113 
114 	RKOptionSetDisplayModel* model;
115 	RKAccordionTable *accordion;
116 
117 	QStackedWidget *switcher;
118 	QWidget *updating_notice;
119 	void updateUnfinishedRows ();
120 	int return_to_row;
121 	QTimer update_timer;
122 
123 	int min_rows;
124 	int min_rows_if_any;
125 	int max_rows;
126 
127 	bool updating;
128 /** Sets the contents from the values in given row */
129 	void setContentsForRow (int row);
130 	void updateCurrentRowInDisplay ();
131 
132 /** get the default value for the given column, row. */
133 	friend QString getDefaultValue (const ColumnInfo& ci, int row);
134 };
135 
136 class RKOptionSetDisplayModel : public QAbstractTableModel {
137 	Q_OBJECT
138 private:
139 friend class RKOptionSet;
140 	explicit RKOptionSetDisplayModel (RKOptionSet* parent);
141 	virtual ~RKOptionSetDisplayModel ();
142 	int rowCount (const QModelIndex & parent = QModelIndex()) const override;
143 	int columnCount (const QModelIndex & parent = QModelIndex()) const override;
144 	QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const override;
145 	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
146 	void triggerReset ();
147 	QTimer reset_timer;
148 	QStringList column_labels;
149 	RKOptionSet *set;
150 
151 	QMimeData* mimeData (const QModelIndexList& indexes) const override;
152 	QStringList mimeTypes () const override;
153 	bool dropMimeData (const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override;
154 	Qt::ItemFlags flags (const QModelIndex& index) const override;
155 	Qt::DropActions supportedDropActions () const override;
156 	Qt::DropActions supportedDragActions () const override;
157 private slots:
158 	void doResetNow ();
159 };
160 
161 #endif
162