1 /*
2     TikZiT - a GUI diagram editor for TikZ
3     Copyright (C) 2018 Aleks Kissinger
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 
19 #include "graphelementdata.h"
20 
21 #include <QDebug>
22 #include <QTextStream>
23 
GraphElementData(QVector<GraphElementProperty> init,QObject * parent)24 GraphElementData::GraphElementData(QVector<GraphElementProperty> init, QObject *parent) : QAbstractItemModel(parent)
25 {
26     _properties = init;
27 }
28 
GraphElementData(QObject * parent)29 GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent) {
30 }
31 
32 
copy()33 GraphElementData *GraphElementData::copy()
34 {
35     return new GraphElementData(_properties);
36 }
37 
setProperty(QString key,QString value)38 void GraphElementData::setProperty(QString key, QString value)
39 {
40     int i = indexOfKey(key);
41     if (i != -1) {
42         _properties[i].setValue(value);
43     } else {
44         GraphElementProperty p(key, value);
45         _properties << p;
46     }
47 }
48 
unsetProperty(QString key)49 void GraphElementData::unsetProperty(QString key)
50 {
51     int i = indexOfKey(key);
52     if (i != -1)
53         _properties.remove(i);
54 }
55 
add(GraphElementProperty p)56 void GraphElementData::add(GraphElementProperty p)
57 {
58     int i = _properties.size();
59     beginInsertRows(QModelIndex(), i, i);
60     _properties << p;
61     endInsertRows();
62 }
63 
operator <<(GraphElementProperty p)64 void GraphElementData::operator <<(GraphElementProperty p)
65 {
66     add(p);
67 }
68 
setAtom(QString atom)69 void GraphElementData::setAtom(QString atom)
70 {
71     int i = indexOfKey(atom);
72     if (i == -1)
73         _properties << GraphElementProperty(atom);
74 }
75 
unsetAtom(QString atom)76 void GraphElementData::unsetAtom(QString atom)
77 {
78     int i = indexOfKey(atom);
79     if (i != -1)
80         _properties.remove(i);
81 }
82 
property(QString key)83 QString GraphElementData::property(QString key)
84 {
85     int i = indexOfKey(key);
86     if (i != -1) {
87         return _properties[i].value();
88     } else {
89         return QString(); // null QString
90     }
91 }
92 
hasProperty(QString key)93 bool GraphElementData::hasProperty(QString key)
94 {
95     return (indexOfKey(key) != -1);
96 }
97 
atom(QString atom)98 bool GraphElementData::atom(QString atom)
99 {
100     int idx = indexOfKey(atom);
101     return (idx != -1 && _properties[idx].atom());
102 }
103 
indexOfKey(QString key)104 int GraphElementData::indexOfKey(QString key)
105 {
106     for (int i = 0; i < _properties.size(); ++i) {
107 		QString key1 = _properties[i].key();
108         if (key1 == key) return i;
109     }
110     return -1;
111 }
112 
mergeData(GraphElementData * d)113 void GraphElementData::mergeData(GraphElementData *d)
114 {
115     GraphElementProperty p;
116     foreach (p, d->properties()) {
117         if (!hasProperty(p.key())) add(p);
118     }
119 }
120 
removeRows(int row,int,const QModelIndex & parent)121 bool GraphElementData::removeRows(int row, int /*count*/, const QModelIndex &parent)
122 {
123     if (row >= 0 && row < _properties.length()) {
124         beginRemoveRows(parent, row, row+1);
125         _properties.remove(row);
126         endRemoveRows();
127         return true;
128     } else {
129         return false;
130     }
131 }
132 
moveRows(const QModelIndex & sourceParent,int sourceRow,int,const QModelIndex & destinationParent,int destinationRow)133 bool GraphElementData::moveRows(const QModelIndex &sourceParent,
134                                 int sourceRow,
135                                 int /*count*/,
136                                 const QModelIndex &destinationParent,
137                                 int destinationRow)
138 {
139     if (sourceRow >= 0 && sourceRow < _properties.length() &&
140         destinationRow >= 0 && destinationRow <= _properties.length())
141     {
142         beginMoveRows(sourceParent, sourceRow, sourceRow, destinationParent, destinationRow);
143         GraphElementProperty p = _properties[sourceRow];
144         _properties.remove(sourceRow);
145         if (sourceRow < destinationRow) {
146             _properties.insert(destinationRow - 1, p);
147         } else {
148             _properties.insert(destinationRow, p);
149         }
150         endMoveRows();
151         return true;
152     } else {
153         return false;
154     }
155 }
156 
data(const QModelIndex & index,int role) const157 QVariant GraphElementData::data(const QModelIndex &index, int role) const
158 {
159     if (role == Qt::DisplayRole || role == Qt::EditRole) {
160         if (index.row() >= 0 && index.row() < _properties.length()) {
161             const GraphElementProperty &p = _properties[index.row()];
162             QString s = (index.column() == 0) ? p.key() : p.value();
163             return QVariant(s);
164         }
165     }
166 
167     return QVariant();
168 }
169 
headerData(int section,Qt::Orientation orientation,int role) const170 QVariant GraphElementData::headerData(int section, Qt::Orientation orientation, int role) const
171 {
172     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
173         if (section == 0) return QVariant("Key/Atom");
174         else return QVariant("Value");
175     }
176 
177     return QVariant();
178 }
179 
index(int row,int column,const QModelIndex &) const180 QModelIndex GraphElementData::index(int row, int column, const QModelIndex &) const
181 {
182     return createIndex(row, column, (void*)0);
183 }
184 
parent(const QModelIndex &) const185 QModelIndex GraphElementData::parent(const QModelIndex &) const
186 {
187     // there is no nesting, so always return an invalid index
188     return QModelIndex();
189 }
190 
rowCount(const QModelIndex & parent) const191 int GraphElementData::rowCount(const QModelIndex &parent) const
192 {
193     if (parent.isValid()) {
194         return 0;
195     } else {
196         return _properties.size();
197     }
198 }
199 
columnCount(const QModelIndex &) const200 int GraphElementData::columnCount(const QModelIndex &) const
201 {
202     return 2;
203 }
204 
flags(const QModelIndex & index) const205 Qt::ItemFlags GraphElementData::flags(const QModelIndex &index) const
206 {
207     if (index.row() >= 0 && index.row() < _properties.length()) {
208         if (index.column() == 0 ||
209             (!_properties[index.row()].atom() && index.column() == 1))
210         {
211             return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
212         }
213     }
214     return QAbstractItemModel::flags(index);
215 }
216 
setData(const QModelIndex & index,const QVariant & value,int role)217 bool GraphElementData::setData(const QModelIndex &index, const QVariant &value, int role)
218 {
219     bool success = false;
220     if (index.row() >= 0 && index.row() < _properties.length()) {
221         if (index.column() == 0) {
222             _properties[index.row()].setKey(value.toString());
223             success = true;
224         } else if (index.column() == 1 && !_properties[index.row()].atom()) {
225             _properties[index.row()].setValue(value.toString());
226             success = true;
227         }
228     }
229 
230     if (success) {
231         QVector<int> roles;
232         roles << role;
233         emit dataChanged(index, index, roles);
234     }
235 
236     return success;
237 }
238 
tikz()239 QString GraphElementData::tikz() {
240     if (_properties.length() == 0) return "";
241     QString str;
242     QTextStream code(&str);
243     code << "[";
244 
245     GraphElementProperty p;
246     bool first = true;
247     foreach(p, _properties) {
248         if (!first) code << ", ";
249         code << p.tikz();
250         first = false;
251     }
252 
253     code << "]";
254 
255     code.flush();
256     return str;
257 }
258 
isEmpty()259 bool GraphElementData::isEmpty()
260 {
261     return _properties.isEmpty();
262 }
263 
properties() const264 QVector<GraphElementProperty> GraphElementData::properties() const
265 {
266     return _properties;
267 }
268 
pathData() const269 GraphElementData *GraphElementData::pathData() const
270 {
271     GraphElementData *d = new GraphElementData();
272     foreach(GraphElementProperty p, _properties) {
273         if (isPathProperty(p.key())) d->add(p);
274     }
275     return d;
276 }
277 
nonPathData() const278 GraphElementData *GraphElementData::nonPathData() const
279 {
280     GraphElementData *d = new GraphElementData();
281     foreach(GraphElementProperty p, _properties) {
282         if (!isPathProperty(p.key())) d->add(p);
283     }
284     return d;
285 }
286 
isPathProperty(QString key)287 bool GraphElementData::isPathProperty(QString key)
288 {
289     return (key == "bend left" ||
290             key == "bend right" ||
291             key == "in" ||
292             key == "out" ||
293             key == "looseness");
294 }
295