25 #include <interfaces/icore.h>
30 #include <KConfigGroup>
31 #include <KLocalizedString>
34 #include <QMimeDatabase>
37 #include <QStandardPaths>
38 #include <QTemporaryDir>
40 using namespace KDevelop;
42 class KDevelop::TemplatesModelPrivate
45 explicit TemplatesModelPrivate(
const QString& typePrefix);
57 void extractTemplateDescriptions();
89 return filter + suffix;
93 TemplatesModelPrivate::TemplatesModelPrivate(
const QString& _typePrefix)
94 : typePrefix(_typePrefix)
103 , d_ptr(new TemplatesModelPrivate(typePrefix))
114 d->templateItems.clear();
116 d->extractTemplateDescriptions();
119 for (
const QString& archivePath : qAsConst(d->searchPaths)) {
121 for (
const QString& file : files) {
122 templateArchives.
append(archivePath + file);
128 {QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
QLatin1Char(
'/') + d->resourceFilter(
129 TemplatesModelPrivate::Description)};
130 for (
const QString& templateDescription : templatePaths) {
132 for (
const QString& file : files) {
133 templateDescriptions.
append(templateDescription + file);
137 for (
const QString& templateDescription : qAsConst(templateDescriptions)) {
139 bool archiveFound =
false;
140 for (
const QString& templateArchive : qAsConst(templateArchives)) {
144 KConfig templateConfig(templateDescription);
145 KConfigGroup general(&templateConfig,
"General");
147 QString category = general.readEntry(
"Category");
148 QString comment = general.readEntry(
"Comment");
150 TemplatesModelPrivate::Preview));
156 templateItem->setData(QVariant::fromValue<TemplatePreviewIcon>(icon),
PreviewIconRole);
174 for (
const QString& entry : path) {
175 currentPath << entry;
178 item->setEditable(
false);
188 templateItem->setEditable(
false);
193 void TemplatesModelPrivate::extractTemplateDescriptions()
196 searchPaths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, resourceFilter(
197 Template), QStandardPaths::LocateDirectory);
198 searchPaths.removeDuplicates();
199 for (
const QString& archivePath : qAsConst(searchPaths)) {
201 for (
const QString& file : files) {
203 QString archfile = archivePath + file;
204 templateArchives.
append(archfile);
209 QString localDescriptionsDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
QLatin1Char(
210 '/') + resourceFilter(Description);
212 QDir dir(localDescriptionsDir);
214 dir.mkpath(QStringLiteral(
"."));
216 for (
const QString& archName : qAsConst(templateArchives)) {
217 qCDebug(LANGUAGE) <<
"processing template" << archName;
221 templateArchive.
reset(
new KZip(archName));
224 templateArchive.
reset(
new KTar(archName));
227 if (templateArchive->open(QIODevice::ReadOnly)) {
240 QString suffix = QStringLiteral(
".kdevtemplate");
241 const KArchiveEntry* templateEntry =
242 templateArchive->directory()->entry(templateInfo.baseName() + suffix);
244 if (!templateEntry || !templateEntry->isFile()) {
251 const auto dirEntries = templateArchive->directory()->entries();
252 for (
const QString& entryName : dirEntries) {
253 if (entryName.endsWith(suffix)) {
254 templateEntry = templateArchive->directory()->entry(entryName);
260 if (!templateEntry || !templateEntry->isFile()) {
261 suffix = QStringLiteral(
".desktop");
262 templateEntry = templateArchive->directory()->entry(templateInfo.baseName() + suffix);
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);
274 if (!templateEntry || !templateEntry->isFile()) {
275 qCDebug(LANGUAGE) <<
"template" << archName <<
"does not contain .kdevtemplate or .desktop file";
278 const auto* templateFile =
static_cast<const KArchiveFile*
>(templateEntry);
280 qCDebug(LANGUAGE) <<
"copy template description to" << localDescriptionsDir;
281 const QString descriptionFileName = templateInfo.baseName() + suffix;
282 if (templateFile->name() == descriptionFileName) {
283 templateFile->copyTo(localDescriptionsDir);
289 templateFile->copyTo(dir.path());
290 const QString destinationPath = localDescriptionsDir + descriptionFileName;
296 qCWarning(LANGUAGE) <<
"could not open template" << archName;
307 QStandardPaths::locate(QStandardPaths::GenericDataLocation,
308 d->resourceFilter(TemplatesModelPrivate::Description,
312 QStandardPaths::locate(QStandardPaths::GenericDataLocation,
313 d->resourceFilter(TemplatesModelPrivate::Description,
317 QModelIndexList indexes;
320 KConfig templateConfig(description);
321 KConfigGroup general(&templateConfig,
"General");
326 for (
const QString& category : categories) {
331 if (!indexes.isEmpty()) {
332 QString name = general.readEntry(
"Name");
334 for (
int i = 0; i < categoryItem->
rowCount(); ++i) {
337 indexes << templateItem->
index();
351 return d->typePrefix;
358 QString realpath = path + d->resourceFilter(TemplatesModelPrivate::Template);
359 d->searchPaths.
append(realpath);
366 QString saveLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
QLatin1Char(
'/') +
367 d->resourceFilter(TemplatesModelPrivate::Template);
369 QDir dir(saveLocation);
371 dir.
mkpath(QStringLiteral(
"."));
376 QMimeType mimeType = QMimeDatabase().mimeTypeForFile(fileName);
377 qCDebug(LANGUAGE) <<
"Loaded file" << fileName <<
"with type" << mimeType.name();
379 if (mimeType.name() ==
QLatin1String(
"application/x-desktop")) {
380 qCDebug(LANGUAGE) <<
"Loaded desktop file" << info.
absoluteFilePath() <<
", compressing";
382 destination +=
".zip";
383 KZip archive(destination);
386 KTar archive(destination, QStringLiteral(
"application/x-bzip"));
389 archive.open(QIODevice::WriteOnly);
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());
404 qCDebug(LANGUAGE) <<
"Copying" << fileName <<
"to" << saveLocation;
QString & append(QChar ch)
QStandardItem * invisibleRootItem() const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
bool rename(const QString &newName)
A class for loading preview images/icons as specified in a template description on demand...
~TemplatesModel() override
Destructor.
QString typePrefix() const
Returns the type prefix used to find a template resource.
QString loadTemplateFile(const QString &fileName)
Loads template fileName and save it to the template storage directory.
QString join(const QString &separator) const
bool copy(const QString &newName)
Template archive file name.
virtual void setData(const QVariant &value, int role)
const char * name() const
void append(const T &value)
Template description file name.
void appendRow(const QList< QStandardItem * > &items)
QFileInfoList entryInfoList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
QString absoluteFilePath() const
QStandardItem * child(int row, int column) const
QModelIndexList templateIndexes(const QString &fileName) const
Finds the model index of the template file fileName.
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
Template preview icon, provides a TemplatePreviewIcon.
QStringList split(const QString &sep, const QString &str, bool allowEmptyEntries)
QModelIndex index() const
TemplatesModel(const QString &typePrefix, QObject *parent=nullptr)
Creates a new templates model.
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
A convenience class for loading templates using .kdevtemplate files.
bool mkpath(const QString &dirPath) const
void addDataPath(const QString &path)
The model will include path during the search for template archives.
virtual void refresh()
Reloads all found templates.