• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevelop/kdevplatform/language/codegen

  • extragear
  • kdevelop
  • kdevelop
  • kdevplatform
  • language
  • codegen
templatesmodel.cpp
Go to the documentation of this file.
1 /* This file is part of KDevelop
2  Copyright 2007 Alexander Dymo <[email protected]>
3  Copyright 2012 Miha Čančula <[email protected]>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library 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 GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20 
21 #include "templatesmodel.h"
22 
23 #include "templatepreviewicon.h"
24 #include <debug.h>
25 #include <interfaces/icore.h>
26 
27 #include <KConfig>
28 #include <KTar>
29 #include <KZip>
30 #include <KConfigGroup>
31 #include <KLocalizedString>
32 
33 #include <QMimeType>
34 #include <QMimeDatabase>
35 #include <QFileInfo>
36 #include <QDir>
37 #include <QStandardPaths>
38 #include <QTemporaryDir>
39 
40 using namespace KDevelop;
41 
42 class KDevelop::TemplatesModelPrivate
43 {
44 public:
45  explicit TemplatesModelPrivate(const QString& typePrefix);
46 
47  QString typePrefix;
48 
49  QStringList searchPaths;
50 
51  QMap<QString, QStandardItem*> templateItems;
52 
57  void extractTemplateDescriptions();
58 
67  QStandardItem* createItem(const QString& name, const QString& category, QStandardItem* parent);
68 
69  enum ResourceType
70  {
71  Description,
72  Template,
73  Preview
74  };
75  QString resourceFilter(ResourceType type, const QString& suffix = QString()) const
76  {
77  QString filter = typePrefix;
78  switch (type) {
79  case Description:
80  filter += QLatin1String("template_descriptions/");
81  break;
82  case Template:
83  filter += QLatin1String("templates/");
84  break;
85  case Preview:
86  filter += QLatin1String("template_previews/");
87  break;
88  }
89  return filter + suffix;
90  }
91 };
92 
93 TemplatesModelPrivate::TemplatesModelPrivate(const QString& _typePrefix)
94  : typePrefix(_typePrefix)
95 {
96  if (!typePrefix.endsWith(QLatin1Char('/'))) {
97  typePrefix.append(QLatin1Char('/'));
98  }
99 }
100 
101 TemplatesModel::TemplatesModel(const QString& typePrefix, QObject* parent)
102  : QStandardItemModel(parent)
103  , d_ptr(new TemplatesModelPrivate(typePrefix))
104 {
105 }
106 
107 TemplatesModel::~TemplatesModel() = default;
108 
109 void TemplatesModel::refresh()
110 {
111  Q_D(TemplatesModel);
112 
113  clear();
114  d->templateItems.clear();
115  d->templateItems[QString()] = invisibleRootItem();
116  d->extractTemplateDescriptions();
117 
118  QStringList templateArchives;
119  for (const QString& archivePath : qAsConst(d->searchPaths)) {
120  const QStringList files = QDir(archivePath).entryList(QDir::Files);
121  for (const QString& file : files) {
122  templateArchives.append(archivePath + file);
123  }
124  }
125 
126  QStringList templateDescriptions;
127  const QStringList templatePaths =
128  {QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + d->resourceFilter(
129  TemplatesModelPrivate::Description)};
130  for (const QString& templateDescription : templatePaths) {
131  const QStringList files = QDir(templateDescription).entryList(QDir::Files);
132  for (const QString& file : files) {
133  templateDescriptions.append(templateDescription + file);
134  }
135  }
136 
137  for (const QString& templateDescription : qAsConst(templateDescriptions)) {
138  QFileInfo fi(templateDescription);
139  bool archiveFound = false;
140  for (const QString& templateArchive : qAsConst(templateArchives)) {
141  if (QFileInfo(templateArchive).baseName() == fi.baseName()) {
142  archiveFound = true;
143 
144  KConfig templateConfig(templateDescription);
145  KConfigGroup general(&templateConfig, "General");
146  QString name = general.readEntry("Name");
147  QString category = general.readEntry("Category");
148  QString comment = general.readEntry("Comment");
149  TemplatePreviewIcon icon(general.readEntry("Icon"), templateArchive, d->resourceFilter(
150  TemplatesModelPrivate::Preview));
151 
152  QStandardItem* templateItem = d->createItem(name, category, invisibleRootItem());
153  templateItem->setData(templateDescription, DescriptionFileRole);
154  templateItem->setData(templateArchive, ArchiveFileRole);
155  templateItem->setData(comment, CommentRole);
156  templateItem->setData(QVariant::fromValue<TemplatePreviewIcon>(icon), PreviewIconRole);
157  }
158  }
159 
160  if (!archiveFound) {
161  // Template file doesn't exist anymore, so remove the description
162  // saves us the extra lookups for templateExists on the next run
163  QFile(templateDescription).remove();
164  }
165  }
166 }
167 
168 QStandardItem* TemplatesModelPrivate::createItem(const QString& name, const QString& category, QStandardItem* parent)
169 {
170  const QStringList path = category.split(QLatin1Char('/'));
171 
172  QStringList currentPath;
173  currentPath.reserve(path.size());
174  for (const QString& entry : path) {
175  currentPath << entry;
176  if (!templateItems.contains(currentPath.join(QLatin1Char('/')))) {
177  auto* item = new QStandardItem(entry);
178  item->setEditable(false);
179  parent->appendRow(item);
180  templateItems[currentPath.join(QLatin1Char('/'))] = item;
181  parent = item;
182  } else {
183  parent = templateItems[currentPath.join(QLatin1Char('/'))];
184  }
185  }
186 
187  auto* templateItem = new QStandardItem(name);
188  templateItem->setEditable(false);
189  parent->appendRow(templateItem);
190  return templateItem;
191 }
192 
193 void TemplatesModelPrivate::extractTemplateDescriptions()
194 {
195  QStringList templateArchives;
196  searchPaths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, resourceFilter(
197  Template), QStandardPaths::LocateDirectory);
198  searchPaths.removeDuplicates();
199  for (const QString& archivePath : qAsConst(searchPaths)) {
200  const QStringList files = QDir(archivePath).entryList(QDir::Files);
201  for (const QString& file : files) {
202  if (file.endsWith(QLatin1String(".zip")) || file.endsWith(QLatin1String(".tar.bz2"))) {
203  QString archfile = archivePath + file;
204  templateArchives.append(archfile);
205  }
206  }
207  }
208 
209  QString localDescriptionsDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char(
210  '/') + resourceFilter(Description);
211 
212  QDir dir(localDescriptionsDir);
213  if (!dir.exists())
214  dir.mkpath(QStringLiteral("."));
215 
216  for (const QString& archName : qAsConst(templateArchives)) {
217  qCDebug(LANGUAGE) << "processing template" << archName;
218 
219  QScopedPointer<KArchive> templateArchive;
220  if (QFileInfo(archName).completeSuffix() == QLatin1String("zip")) {
221  templateArchive.reset(new KZip(archName));
222  } else
223  {
224  templateArchive.reset(new KTar(archName));
225  }
226 
227  if (templateArchive->open(QIODevice::ReadOnly)) {
228  /*
229  * This class looks for template description files in the following order
230  *
231  * - "basename.kdevtemplate"
232  * - "*.kdevtemplate"
233  * - "basename.desktop"
234  * - "*.desktop"
235  *
236  * This is done because application templates can contain .desktop files used by the application
237  * so the kdevtemplate suffix must have priority.
238  */
239  QFileInfo templateInfo(archName);
240  QString suffix = QStringLiteral(".kdevtemplate");
241  const KArchiveEntry* templateEntry =
242  templateArchive->directory()->entry(templateInfo.baseName() + suffix);
243 
244  if (!templateEntry || !templateEntry->isFile()) {
245  /*
246  * First, if the .kdevtemplate file is not found by name,
247  * we check all the files in the archive for any .kdevtemplate file
248  *
249  * This is needed because kde-files.org renames downloaded files
250  */
251  const auto dirEntries = templateArchive->directory()->entries();
252  for (const QString& entryName : dirEntries) {
253  if (entryName.endsWith(suffix)) {
254  templateEntry = templateArchive->directory()->entry(entryName);
255  break;
256  }
257  }
258  }
259 
260  if (!templateEntry || !templateEntry->isFile()) {
261  suffix = QStringLiteral(".desktop");
262  templateEntry = templateArchive->directory()->entry(templateInfo.baseName() + suffix);
263  }
264 
265  if (!templateEntry || !templateEntry->isFile()) {
266  const auto dirEntries = templateArchive->directory()->entries();
267  for (const QString& entryName : dirEntries) {
268  if (entryName.endsWith(suffix)) {
269  templateEntry = templateArchive->directory()->entry(entryName);
270  break;
271  }
272  }
273  }
274  if (!templateEntry || !templateEntry->isFile()) {
275  qCDebug(LANGUAGE) << "template" << archName << "does not contain .kdevtemplate or .desktop file";
276  continue;
277  }
278  const auto* templateFile = static_cast<const KArchiveFile*>(templateEntry);
279 
280  qCDebug(LANGUAGE) << "copy template description to" << localDescriptionsDir;
281  const QString descriptionFileName = templateInfo.baseName() + suffix;
282  if (templateFile->name() == descriptionFileName) {
283  templateFile->copyTo(localDescriptionsDir);
284  } else {
285  // Rename the extracted description
286  // so that its basename matches the basename of the template archive
287  // Use temporary dir to not overwrite other files with same name
288  QTemporaryDir dir;
289  templateFile->copyTo(dir.path());
290  const QString destinationPath = localDescriptionsDir + descriptionFileName;
291  QFile::remove(destinationPath);
292  QFile::rename(dir.path() + QLatin1Char('/') + templateFile->name(), destinationPath);
293  }
294  } else
295  {
296  qCWarning(LANGUAGE) << "could not open template" << archName;
297  }
298  }
299 }
300 
301 QModelIndexList TemplatesModel::templateIndexes(const QString& fileName) const
302 {
303  Q_D(const TemplatesModel);
304 
305  QFileInfo info(fileName);
306  QString description =
307  QStandardPaths::locate(QStandardPaths::GenericDataLocation,
308  d->resourceFilter(TemplatesModelPrivate::Description,
309  info.baseName() + QLatin1String(".kdevtemplate")));
310  if (description.isEmpty()) {
311  description =
312  QStandardPaths::locate(QStandardPaths::GenericDataLocation,
313  d->resourceFilter(TemplatesModelPrivate::Description,
314  info.baseName() + QLatin1String(".desktop")));
315  }
316 
317  QModelIndexList indexes;
318 
319  if (!description.isEmpty()) {
320  KConfig templateConfig(description);
321  KConfigGroup general(&templateConfig, "General");
322  const QStringList categories = general.readEntry("Category").split(QLatin1Char('/'));
323 
324  QStringList levels;
325  levels.reserve(categories.size());
326  for (const QString& category : categories) {
327  levels << category;
328  indexes << d->templateItems[levels.join(QLatin1Char('/'))]->index();
329  }
330 
331  if (!indexes.isEmpty()) {
332  QString name = general.readEntry("Name");
333  QStandardItem* categoryItem = d->templateItems[levels.join(QLatin1Char('/'))];
334  for (int i = 0; i < categoryItem->rowCount(); ++i) {
335  QStandardItem* templateItem = categoryItem->child(i);
336  if (templateItem->text() == name) {
337  indexes << templateItem->index();
338  break;
339  }
340  }
341  }
342  }
343 
344  return indexes;
345 }
346 
347 QString TemplatesModel::typePrefix() const
348 {
349  Q_D(const TemplatesModel);
350 
351  return d->typePrefix;
352 }
353 
354 void TemplatesModel::addDataPath(const QString& path)
355 {
356  Q_D(TemplatesModel);
357 
358  QString realpath = path + d->resourceFilter(TemplatesModelPrivate::Template);
359  d->searchPaths.append(realpath);
360 }
361 
362 QString TemplatesModel::loadTemplateFile(const QString& fileName)
363 {
364  Q_D(TemplatesModel);
365 
366  QString saveLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') +
367  d->resourceFilter(TemplatesModelPrivate::Template);
368 
369  QDir dir(saveLocation);
370  if (!dir.exists())
371  dir.mkpath(QStringLiteral("."));
372 
373  QFileInfo info(fileName);
374  QString destination = saveLocation + info.baseName();
375 
376  QMimeType mimeType = QMimeDatabase().mimeTypeForFile(fileName);
377  qCDebug(LANGUAGE) << "Loaded file" << fileName << "with type" << mimeType.name();
378 
379  if (mimeType.name() == QLatin1String("application/x-desktop")) {
380  qCDebug(LANGUAGE) << "Loaded desktop file" << info.absoluteFilePath() << ", compressing";
381 #ifdef Q_WS_WIN
382  destination += ".zip";
383  KZip archive(destination);
384 #else
385  destination += QLatin1String(".tar.bz2");
386  KTar archive(destination, QStringLiteral("application/x-bzip"));
387 #endif //Q_WS_WIN
388 
389  archive.open(QIODevice::WriteOnly);
390 
391  QDir dir(info.absoluteDir());
392  const auto dirEntryInfos = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
393  for (const QFileInfo& entry : dirEntryInfos) {
394  if (entry.isFile()) {
395  archive.addLocalFile(entry.absoluteFilePath(), entry.fileName());
396  } else if (entry.isDir()) {
397  archive.addLocalDirectory(entry.absoluteFilePath(), entry.fileName());
398  }
399  }
400 
401  archive.close();
402  } else
403  {
404  qCDebug(LANGUAGE) << "Copying" << fileName << "to" << saveLocation;
405  QFile::copy(fileName, saveLocation + info.fileName());
406  }
407 
408  refresh();
409 
410  return destination;
411 }
QStandardItemModel
QString::append
QString & append(QChar ch)
QStandardItemModel::invisibleRootItem
QStandardItem * invisibleRootItem() const
templatesmodel.h
QFile::remove
bool remove()
QStandardItemModel::clear
void clear()
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QList::reserve
void reserve(int alloc)
QMap< QString, QStandardItem * >
QFile::rename
bool rename(const QString &newName)
KDevelop::TemplatePreviewIcon
A class for loading preview images/icons as specified in a template description on demand...
Definition: templatepreviewicon.h:46
KDevelop::TemplatesModel::~TemplatesModel
~TemplatesModel() override
Destructor.
KDevelop::TemplatesModel::typePrefix
QString typePrefix() const
Returns the type prefix used to find a template resource.
Definition: templatesmodel.cpp:347
KDevelop::TemplatesModel::loadTemplateFile
QString loadTemplateFile(const QString &fileName)
Loads template fileName and save it to the template storage directory.
Definition: templatesmodel.cpp:362
QStringList::join
QString join(const QString &separator) const
QStandardItem::text
QString text() const
QFile
QFile::copy
bool copy(const QString &newName)
KDevelop::TemplatesModel::ArchiveFileRole
Template archive file name.
Definition: templatesmodel.h:63
QList::size
int size() const
QStandardItem::setData
virtual void setData(const QVariant &value, int role)
QScopedPointer::reset
void reset(T *other)
KDevelop::TemplatesModel::CommentRole
Template comment.
Definition: templatesmodel.h:62
QObject::name
const char * name() const
QDir::exists
bool exists() const
QList::append
void append(const T &value)
QFileInfo::fileName
QString fileName() const
KDevelop::TemplatesModel::DescriptionFileRole
Template description file name.
Definition: templatesmodel.h:60
QObject
QScopedPointer
QStandardItem::appendRow
void appendRow(const QList< QStandardItem * > &items)
QDir::entryInfoList
QFileInfoList entryInfoList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
QFileInfo::absoluteFilePath
QString absoluteFilePath() const
QString::isEmpty
bool isEmpty() const
QFileInfo::absoluteDir
QDir absoluteDir() const
QString
QStandardItem::child
QStandardItem * child(int row, int column) const
QStringList
QFileInfo
templatepreviewicon.h
QLatin1Char
KDevelop::TemplatesModel::templateIndexes
QModelIndexList templateIndexes(const QString &fileName) const
Finds the model index of the template file fileName.
Definition: templatesmodel.cpp:301
QDir
QLatin1String
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
KDevelop::TemplatesModel::PreviewIconRole
Template preview icon, provides a TemplatePreviewIcon.
Definition: templatesmodel.h:61
QStringList::split
QStringList split(const QString &sep, const QString &str, bool allowEmptyEntries)
QStandardItem::index
QModelIndex index() const
QStandardItem::rowCount
int rowCount() const
KDevelop::TemplatesModel::TemplatesModel
TemplatesModel(const QString &typePrefix, QObject *parent=nullptr)
Creates a new templates model.
Definition: templatesmodel.cpp:101
QtConcurrent::filter
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
QStandardItem
KDevelop::TemplatesModel
A convenience class for loading templates using .kdevtemplate files.
Definition: templatesmodel.h:47
QFileInfo::baseName
QString baseName() const
QDir::mkpath
bool mkpath(const QString &dirPath) const
KDevelop::TemplatesModel::addDataPath
void addDataPath(const QString &path)
The model will include path during the search for template archives.
Definition: templatesmodel.cpp:354
KDevelop::TemplatesModel::refresh
virtual void refresh()
Reloads all found templates.
Definition: templatesmodel.cpp:109
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Thu Dec 12 2019 03:33:20 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevelop/kdevplatform/language/codegen

Skip menu "kdevelop/kdevplatform/language/codegen"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  •   kdevplatform
  •     debugger
  •     documentation
  •     interfaces
  •     language
  •       assistant
  •       backgroundparser
  •       checks
  •       classmodel
  •       codecompletion
  •       codegen
  •       duchain
  •       editor
  •       highlighting
  •       interfaces
  •       util
  •     outputview
  •     project
  •     serialization
  •     shell
  •     sublime
  •     tests
  •     util
  •     vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal