1 /*
2 Drawpile - a collaborative drawing program.
3
4 Copyright (C) 2014-2015 Calle Laakkonen
5
6 Drawpile is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Drawpile is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Drawpile. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "palettelistmodel.h"
21 #include "palette.h"
22 #include "icon.h"
23 #include "../libshared/util/paths.h"
24
25 #include <QDebug>
26 #include <QFileInfo>
27 #include <QDir>
28
PaletteListModel(QObject * parent)29 PaletteListModel::PaletteListModel(QObject *parent) :
30 QAbstractListModel(parent),
31 _readonlyEmblem(icon::fromTheme("object-locked"))
32 {
33 }
34
getSharedInstance()35 PaletteListModel *PaletteListModel::getSharedInstance()
36 {
37 static PaletteListModel *instance;
38 if(!instance) {
39 instance = new PaletteListModel;
40 instance->loadPalettes();
41 }
42 return instance;
43 }
44
loadPalettes()45 void PaletteListModel::loadPalettes()
46 {
47 QList<Palette*> palettes;
48
49 const QStringList datapaths = utils::paths::dataPaths();
50 const QString writablepath = utils::paths::writablePath(QString());
51 QSet<QString> palettefiles;
52
53 for(const QString &datapath : datapaths) {
54 QFileInfoList pfiles = QDir(datapath + "/palettes").entryInfoList(
55 QStringList("*.gpl"),
56 QDir::Files|QDir::Readable
57 );
58
59 for(const QFileInfo &pfile : pfiles) {
60 if(!palettefiles.contains(pfile.fileName())) {
61 palettefiles.insert(pfile.fileName());
62
63 // QFile::isWritable doesn't seem to work reliably on Windows.
64 // As a workaround, mark all palettes outside our own writable directory
65 // as read-only
66
67 Palette *pal = Palette::fromFile(pfile, datapath != writablepath, this);
68 if(!pal)
69 qWarning() << "Invalid palette:" << pfile.absoluteFilePath();
70
71 else
72 palettes.append(pal);
73 }
74 }
75 }
76
77 beginResetModel();
78 _palettes = palettes;
79 endResetModel();
80 }
81
saveChanged()82 void PaletteListModel::saveChanged()
83 {
84 for(Palette *pal : _palettes) {
85 if(pal->isModified())
86 pal->save();
87 }
88 }
89
rowCount(const QModelIndex & parent) const90 int PaletteListModel::rowCount(const QModelIndex &parent) const
91 {
92 if(parent.isValid())
93 return 0;
94
95 return _palettes.size();
96 }
97
data(const QModelIndex & index,int role) const98 QVariant PaletteListModel::data(const QModelIndex &index, int role) const
99 {
100 if(index.isValid() && index.row() >= 0 && index.row() < _palettes.size()) {
101 switch(role) {
102 case Qt::DisplayRole:
103 case Qt::EditRole:
104 return _palettes.at(index.row())->name();
105 case Qt::DecorationRole:
106 if(_palettes.at(index.row())->isReadonly())
107 return _readonlyEmblem;
108 break;
109 }
110 }
111
112 return QVariant();
113 }
114
setData(const QModelIndex & index,const QVariant & value,int role)115 bool PaletteListModel::setData(const QModelIndex &index, const QVariant &value, int role)
116 {
117 if(role==Qt::EditRole && index.isValid() && index.row() >= 0 && index.row() < _palettes.size()) {
118 QString newname = value.toString().trimmed();
119
120 if(_palettes[index.row()]->isReadonly())
121 return false;
122
123 // Name must be non-empty and unique
124 if(newname.isEmpty() || !isUniqueName(newname, index.row()))
125 return false;
126
127 _palettes[index.row()]->setName(value.toString());
128 emit dataChanged(index, index);
129 return true;
130 }
131 return false;
132 }
133
flags(const QModelIndex & index) const134 Qt::ItemFlags PaletteListModel::flags(const QModelIndex &index) const
135 {
136 Qt::ItemFlags f = Qt::NoItemFlags;
137 if(index.isValid() && index.row() >= 0 && index.row() < _palettes.size()) {
138 f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
139
140 if(!_palettes.at(index.row())->isReadonly())
141 f |= Qt::ItemIsEditable;
142 }
143
144 return f;
145 }
146
getPalette(int index)147 Palette *PaletteListModel::getPalette(int index)
148 {
149 Q_ASSERT(index>=0 && index<_palettes.size());
150 if(index>=0 && index<_palettes.size())
151 return _palettes[index];
152
153 return nullptr;
154 }
155
findPalette(const QString & name) const156 int PaletteListModel::findPalette(const QString &name) const
157 {
158 for(int i=0;i<_palettes.size();++i)
159 if(_palettes.at(i)->name() == name)
160 return i;
161 return -1;
162 }
163
addNewPalette()164 void PaletteListModel::addNewPalette()
165 {
166 QString name;
167 bool nameOk = false;
168
169 // Autogenerate name
170 for(int tries=0;tries<99;++tries) {
171 name = tr("New palette");
172 if(tries>0)
173 name = name + " " + QString::number(tries);
174
175 if(isUniqueName(name)) {
176 // name found
177 nameOk = true;
178 break;
179 }
180 }
181
182 if(!nameOk)
183 return;
184
185 int pos = _palettes.size();
186 beginInsertRows(QModelIndex(), pos, pos);
187 _palettes.append(new Palette(name, this));
188 endInsertRows();
189 }
190
copyPalette(int index)191 bool PaletteListModel::copyPalette(int index)
192 {
193 if(index<0 || index >= _palettes.size())
194 return false;
195
196 const Palette *pal = _palettes.at(index);
197
198 QString basename = pal->name();
199 while(basename.size()>0 && (basename.at(basename.size()-1).isDigit() || basename.at(basename.size()-1).isSpace()))
200 basename.chop(1);
201 basename.append(' ');
202
203 QString name;
204 for(int tries=2;tries<99;++tries) {
205 QString newname = basename + QString::number(tries);
206
207 if(isUniqueName(newname)) {
208 name = newname;
209 break;
210 }
211 }
212
213 if(name.isNull())
214 return false;
215
216 Palette *copy = Palette::copy(pal, name, this);
217 beginInsertRows(QModelIndex(), index, index);
218 _palettes.insert(index, copy);
219 endInsertRows();
220
221 return true;
222 }
223
isUniqueName(const QString & name,int exclude) const224 bool PaletteListModel::isUniqueName(const QString &name, int exclude) const
225 {
226 for(int i=0;i<_palettes.size();++i)
227 if(i != exclude && _palettes.at(i)->name().compare(name, Qt::CaseInsensitive) == 0)
228 return false;
229 return true;
230 }
231
removeRows(int row,int count,const QModelIndex & parent)232 bool PaletteListModel::removeRows(int row, int count, const QModelIndex &parent)
233 {
234 if(parent.isValid() || row < 0 || row+count > _palettes.size())
235 return false;
236
237 beginRemoveRows(parent, row, row+count-1);
238
239 while(count-->0) {
240 Palette *pal = _palettes.takeAt(row);
241 pal->deleteFile();
242 delete pal;
243 }
244
245 endRemoveRows();
246 return true;
247 }
248