1 /*
2     SPDX-FileCopyrightText: 2006-2010 Peter Hedlund <peter.hedlund@kdemail.net>
3     SPDX-License-Identifier: GPL-2.0-or-later
4 */
5 
6 #include "kwqtablemodel.h"
7 
8 #include <KLocalizedString>
9 
10 #include "prefs.h"
11 #include "documentsettings.h"
12 #include "keduvocexpression.h"
13 
KWQTableModel(QObject * parent)14 KWQTableModel::KWQTableModel(QObject * parent) : QAbstractTableModel(parent)
15 {
16   m_doc = 0;
17   m_decorationCache = new KImageCache(QStringLiteral("kwordquiz"), 10485760);
18 }
19 
~KWQTableModel()20 KWQTableModel::~KWQTableModel()
21 {
22   delete m_decorationCache;
23 }
24 
rowCount(const QModelIndex & parent) const25 int KWQTableModel::rowCount(const QModelIndex & parent) const
26 {
27   if (parent.isValid())
28     return 0;
29   return m_doc->lesson()->entryCount(KEduVocLesson::Recursive);
30 }
31 
columnCount(const QModelIndex & parent) const32 int KWQTableModel::columnCount(const QModelIndex & parent) const
33 {
34   if (parent.isValid())
35     return 0;
36   return 2;
37 }
38 
data(const QModelIndex & index,int role) const39 QVariant KWQTableModel::data(const QModelIndex & index, int role) const
40 {
41   if (!index.isValid())
42     return QVariant();
43 
44   QPixmap ip;
45   QString image;
46 
47   switch (role) {
48     case Qt::FontRole:
49       return QVariant(Prefs::editorFont());
50 
51     case Qt::DisplayRole:
52       return m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->text();
53 
54     case Qt::DecorationRole:
55       image = m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->imageUrl().toLocalFile();
56       if (!image.isEmpty()) {
57         if (!m_decorationCache->findPixmap(image, &ip)) {
58           ip = QPixmap(image).scaled(QSize(22, 22), Qt::KeepAspectRatio);
59           m_decorationCache->insertPixmap(image, ip);
60         }
61       }
62       return ip;
63 
64     case KWQTableModel::ImageRole:
65       return m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->imageUrl().toLocalFile();
66 
67     case KWQTableModel::SoundRole:
68       return m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->soundUrl().toLocalFile();
69 
70     default:
71       return QVariant();
72   }
73 }
74 
headerData(int section,Qt::Orientation orientation,int role) const75 QVariant KWQTableModel::headerData(int section, Qt::Orientation orientation, int role) const
76 {
77   if (orientation == Qt::Horizontal)
78   {
79     if (section < 0 || section > 1)
80       return QVariant();
81 
82     if (role == Qt::DisplayRole) {
83       return m_doc->identifier(section).name();
84     }
85 
86     if (role == Qt::SizeHintRole) {
87       DocumentSettings documentSettings(m_doc->url().url());
88       documentSettings.read();
89       return QSize(documentSettings.sizeHintColumn(section), 25);
90     }
91 
92     if (role == KWQTableModel::KeyboardLayoutRole) {
93       DocumentSettings documentSettings(m_doc->url().url());
94       documentSettings.read();
95       return documentSettings.keyboardLayoutColumn(section);
96     }
97 
98     return QVariant();
99   }
100   else
101     return QAbstractTableModel::headerData(section, orientation, role);
102 }
103 
flags(const QModelIndex & index) const104 Qt::ItemFlags KWQTableModel::flags(const QModelIndex & index) const
105 {
106   if (!index.isValid())
107     return Qt::ItemIsEnabled;
108 
109   return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
110 }
111 
setData(const QModelIndex & index,const QVariant & value,int role)112 bool KWQTableModel::setData(const QModelIndex & index, const QVariant & value, int role)
113 {
114   if (!index.isValid())
115     return false;
116 
117   switch (role) {
118     case Qt::EditRole:
119       m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->setTranslation(index.column(), value.toString());
120       break;
121 
122     case KWQTableModel::ImageRole:
123       m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->setImageUrl(value.toUrl());
124       break;
125 
126     case KWQTableModel::SoundRole:
127       m_doc->lesson()->entries(KEduVocLesson::Recursive).value(index.row())->translation(index.column())->setSoundUrl(value.toUrl());
128       break;
129   }
130 
131   Q_EMIT dataChanged(index, index);
132   return true;
133 }
134 
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)135 bool KWQTableModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant & value, int role)
136 {
137   if (orientation == Qt::Horizontal) {
138     if (section < 0 || section > 1)
139       return false;
140 
141     if (role == Qt::EditRole) {
142       m_doc->identifier(section).setName(value.toString());
143     }
144 
145     if (role == Qt::SizeHintRole) {
146       DocumentSettings documentSettings(m_doc->url().url());
147       documentSettings.setSizeHintColumn(section, qvariant_cast<QSize>(value).width());
148       documentSettings.save();
149     }
150 
151     if (role == KWQTableModel::KeyboardLayoutRole) {
152       DocumentSettings documentSettings(m_doc->url().url());
153       documentSettings.setKeyboardLayoutColumn(section, value.toString());
154       documentSettings.save();
155     }
156 
157     Q_EMIT headerDataChanged(orientation, section, section);
158     return true;
159   }
160   return false;
161 }
162 
163 
insertRows(int row,int count,const QModelIndex & parent)164 bool KWQTableModel::insertRows(int row, int count, const QModelIndex & parent)
165 {
166   Q_UNUSED(parent);
167   if (count < 1 || row < 0 || row > m_doc->lesson()->entryCount(KEduVocLesson::Recursive))
168     return false;
169 
170   KEduVocLesson * cl = currentLesson(row);
171 
172   beginInsertRows(QModelIndex(), row, row + count - 1);
173 
174   for (int i = row; i < row + count; i++)
175     cl->insertEntry(i, new KEduVocExpression); //m_doc->lesson()->insertEntry(i, new KEduVocExpression);
176 
177   endInsertRows();
178   m_doc->setModified(true);
179   return true;
180 }
181 
removeRows(int row,int count,const QModelIndex & parent)182 bool KWQTableModel::removeRows(int row, int count, const QModelIndex & parent)
183 {
184   Q_UNUSED(parent);
185   if (count < 1 || row < 0 || row + count > m_doc->lesson()->entryCount(KEduVocLesson::Recursive) || count >= m_doc->lesson()->entryCount(KEduVocLesson::Recursive))
186     return false;
187 
188   int bottomRow = row + count -1;
189   beginRemoveRows(QModelIndex(), row, row + count - 1);
190 
191   for (int i = bottomRow; i >= row; i--) {
192     KEduVocExpression* entry = m_doc->lesson()->entries(KEduVocLesson::Recursive).value(i);
193     entry->lesson()->removeEntry(entry);
194     delete entry;
195   }
196 
197   endRemoveRows();
198   m_doc->setModified(true);
199   return true;
200 }
201 
setDocument(KEduVocDocument * doc)202 void KWQTableModel::setDocument(KEduVocDocument * doc)
203 {
204   beginResetModel();
205   m_doc = doc;
206   endResetModel();
207 }
208 
isEmpty()209 bool KWQTableModel::isEmpty()
210 {
211   if (m_doc->url().fileName() == i18n("Untitled")){
212     int rc = rowCount(QModelIndex());
213     for (int i = 0; i < rc; i++)
214       if (!data(index(i, 0), Qt::DisplayRole).toString().isEmpty() || !data(index(i, 1), Qt::DisplayRole).toString().isEmpty())
215         return false;
216 
217     return true;
218   }
219   else
220     return false;
221 }
222 
223 
checkBlanksSyntax(const QString & text) const224 bool KWQTableModel::checkBlanksSyntax(const QString & text) const
225 {
226   if (!Prefs::enableBlanks())
227     return true;
228 
229   bool result = false;
230   int openCount = 0;
231   int closeCount = 0;
232   QVector<int> openPos(0);
233   QVector<int> closePos(0);
234 
235   for (int i = 0; i< text.length(); ++i)
236   {
237     if (text[i] == delim_start)
238     {
239       openCount++;
240       openPos.resize(openCount);
241       openPos[openCount - 1] = i;
242     }
243 
244     if (text[i] == delim_end)
245     {
246       closeCount++;
247       closePos.resize(closeCount);
248       closePos[closeCount - 1] = i;
249     }
250   }
251 
252   if (openCount == 0 && closeCount == 0)
253     return true;
254 
255   if (openCount > 0 && closeCount > 0)
256     if (openPos.size() == closePos.size())
257       for (int i = 0; i < openPos.size(); ++i)
258         result = (openPos[i] < closePos[i]);
259 
260   return result;
261 }
262 
checkSyntax() const263 bool KWQTableModel::checkSyntax() const
264 {
265   int errorCount = 0;
266 
267   for (int r = 0; r < rowCount(QModelIndex()); ++r)
268   {
269     QString s = data(index(r, 0, QModelIndex()), Qt::DisplayRole).toString();
270     if (s.length() > 0)
271       for (int i = 0; i <= s.length(); ++i)
272         if (s[i] == delim_start || s[i] == delim_end)
273           if (!checkBlanksSyntax(s))
274             errorCount++;
275     s = data(index(r, 1, QModelIndex()), Qt::DisplayRole).toString();
276     if (s.length() > 0)
277       for (int i = 0; i <= s.length(); ++i)
278         if (s[i] == delim_start || s[i] == delim_end)
279           if (!checkBlanksSyntax(s))
280             errorCount++;
281   }
282 
283   return (errorCount == 0);
284 }
285 
currentLesson(int row)286 KEduVocLesson * KWQTableModel::currentLesson(int row)
287 {
288   int i = 0;
289   QList<KEduVocContainer *>  lessons = m_doc->lesson()->childContainers();
290   foreach(KEduVocContainer * c, lessons) {
291     if (c->containerType() == KEduVocLesson::Lesson) {
292       i += c->entryCount();
293       if (i >= row)
294         return static_cast<KEduVocLesson *>(c);
295     }
296   }
297   return m_doc->lesson();
298 }
299