File indexing completed on 2024-04-28 04:37:48
0001 /* 0002 SPDX-FileCopyrightText: 2001 Bernd Gehrmann <bernd@kdevelop.org> 0003 SPDX-FileCopyrightText: 2004-2005 Sascha Cunz <sascha@kdevelop.org> 0004 SPDX-FileCopyrightText: 2005 Ian Reinhart Geiser <ian@geiseri.com> 0005 SPDX-FileCopyrightText: 2007 Alexander Dymo <adymo@kdevelop.org> 0006 SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "appwizardplugin.h" 0012 0013 #include <QAction> 0014 #include <QDir> 0015 #include <QDirIterator> 0016 #include <QFile> 0017 #include <QFileInfo> 0018 #include <QMimeType> 0019 #include <QMimeDatabase> 0020 #include <QStandardPaths> 0021 #include <QTemporaryDir> 0022 #include <QTextCodec> 0023 #include <QTextStream> 0024 #include <qplatformdefs.h> 0025 0026 #include <KActionCollection> 0027 #include <KConfigGroup> 0028 #include <KIO/CopyJob> 0029 #include <KIO/DeleteJob> 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <KParts/MainWindow> 0033 #include <KPluginFactory> 0034 #include <KSharedConfig> 0035 #include <KTar> 0036 #include <KZip> 0037 #include <KMacroExpander> 0038 0039 #include <interfaces/icore.h> 0040 #include <interfaces/iprojectcontroller.h> 0041 #include <interfaces/iplugincontroller.h> 0042 #include <interfaces/iuicontroller.h> 0043 #include <interfaces/idocumentcontroller.h> 0044 #include <interfaces/context.h> 0045 #include <interfaces/contextmenuextension.h> 0046 #include <util/scopeddialog.h> 0047 #include <sublime/message.h> 0048 #include <vcs/vcsjob.h> 0049 #include <vcs/interfaces/icentralizedversioncontrol.h> 0050 #include <vcs/interfaces/idistributedversioncontrol.h> 0051 0052 #include "appwizarddialog.h" 0053 #include "projectselectionpage.h" 0054 #include "projectvcspage.h" 0055 #include "projecttemplatesmodel.h" 0056 #include "debug.h" 0057 0058 using namespace KDevelop; 0059 0060 K_PLUGIN_FACTORY_WITH_JSON(AppWizardFactory, "kdevappwizard.json", registerPlugin<AppWizardPlugin>();) 0061 0062 AppWizardPlugin::AppWizardPlugin(QObject *parent, const QVariantList &) 0063 : KDevelop::IPlugin(QStringLiteral("kdevappwizard"), parent) 0064 { 0065 setXMLFile(QStringLiteral("kdevappwizard.rc")); 0066 0067 m_newFromTemplate = actionCollection()->addAction(QStringLiteral("project_new")); 0068 m_newFromTemplate->setIcon(QIcon::fromTheme(QStringLiteral("project-development-new-template"))); 0069 m_newFromTemplate->setText(i18nc("@action", "New from Template...")); 0070 connect(m_newFromTemplate, &QAction::triggered, this, &AppWizardPlugin::slotNewProject); 0071 m_newFromTemplate->setToolTip( i18nc("@info:tooltip", "Generate a new project from a template") ); 0072 m_newFromTemplate->setWhatsThis( i18nc("@info:whatsthis", "This starts KDevelop's application wizard. " 0073 "It helps you to generate a skeleton for your " 0074 "application from a set of templates.") ); 0075 } 0076 0077 AppWizardPlugin::~AppWizardPlugin() 0078 { 0079 } 0080 0081 void AppWizardPlugin::slotNewProject() 0082 { 0083 model()->refresh(); 0084 0085 ScopedDialog<AppWizardDialog> dlg(core()->pluginController(), m_templatesModel); 0086 0087 if (dlg->exec() == QDialog::Accepted) 0088 { 0089 QString project = createProject( dlg->appInfo() ); 0090 if (!project.isEmpty()) 0091 { 0092 core()->projectController()->openProject(QUrl::fromLocalFile(project)); 0093 0094 KConfig templateConfig(dlg->appInfo().appTemplate); 0095 KConfigGroup general(&templateConfig, "General"); 0096 const QStringList fileArgs = 0097 general.readEntry("ShowFilesAfterGeneration").split(QLatin1Char(','), Qt::SkipEmptyParts); 0098 for (const auto& fileArg : fileArgs) { 0099 QString file = KMacroExpander::expandMacros(fileArg.trimmed(), m_variables); 0100 if (QDir::isRelativePath(file)) { 0101 file = m_variables[QStringLiteral("PROJECTDIR")] + QLatin1Char('/') + file; 0102 } 0103 core()->documentController()->openDocument(QUrl::fromUserInput(file)); 0104 } 0105 } else { 0106 const QString messageText = i18n("Could not create project from template."); 0107 auto* message = new Sublime::Message(messageText, Sublime::Message::Error); 0108 ICore::self()->uiController()->postMessage(message); 0109 } 0110 } 0111 } 0112 0113 namespace 0114 { 0115 0116 IDistributedVersionControl* toDVCS(IPlugin* plugin) 0117 { 0118 Q_ASSERT(plugin); 0119 return plugin->extension<IDistributedVersionControl>(); 0120 } 0121 0122 ICentralizedVersionControl* toCVCS(IPlugin* plugin) 0123 { 0124 Q_ASSERT(plugin); 0125 return plugin->extension<ICentralizedVersionControl>(); 0126 } 0127 0128 /*! Trouble while initializing version control. Show failure message to user. */ 0129 void vcsError(const QString &errorMsg, QTemporaryDir &tmpdir, const QUrl &dest, const QString &details = QString()) 0130 { 0131 QString displayDetails = details; 0132 if (displayDetails.isEmpty()) 0133 { 0134 displayDetails = i18n("Please see the Version Control tool view."); 0135 } 0136 KMessageBox::detailedError(nullptr, errorMsg, displayDetails, i18nc("@title:window", "Version Control System Error")); 0137 KIO::del(dest, KIO::HideProgressInfo)->exec(); 0138 tmpdir.remove(); 0139 } 0140 0141 /*! Setup distributed version control for a new project defined by @p info. Use @p scratchArea for temporary files */ 0142 bool initializeDVCS(IDistributedVersionControl* dvcs, const ApplicationInfo& info, QTemporaryDir& scratchArea) 0143 { 0144 Q_ASSERT(dvcs); 0145 qCDebug(PLUGIN_APPWIZARD) << "DVCS system is used, just initializing DVCS"; 0146 0147 const QUrl& dest = info.location; 0148 //TODO: check if we want to handle KDevelop project files (like now) or only SRC dir 0149 VcsJob* job = dvcs->init(dest); 0150 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded) 0151 { 0152 vcsError(i18n("Could not initialize DVCS repository"), scratchArea, dest); 0153 return false; 0154 } 0155 qCDebug(PLUGIN_APPWIZARD) << "Initializing DVCS repository:" << dest; 0156 0157 qCDebug(PLUGIN_APPWIZARD) << "Checking for valid files in the DVCS repository:" << dest; 0158 job = dvcs->status({dest}, KDevelop::IBasicVersionControl::Recursive); 0159 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded) 0160 { 0161 vcsError(i18n("Could not check status of the DVCS repository"), scratchArea, dest); 0162 return false; 0163 } 0164 0165 if (job->fetchResults().toList().isEmpty()) 0166 { 0167 qCDebug(PLUGIN_APPWIZARD) << "No files to add, skipping commit in the DVCS repository:" << dest; 0168 return true; 0169 } 0170 0171 job = dvcs->add({dest}, KDevelop::IBasicVersionControl::Recursive); 0172 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded) 0173 { 0174 vcsError(i18n("Could not add files to the DVCS repository"), scratchArea, dest); 0175 return false; 0176 } 0177 0178 job = dvcs->commit(info.importCommitMessage, {dest}, 0179 KDevelop::IBasicVersionControl::Recursive); 0180 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded) 0181 { 0182 vcsError(i18n("Could not import project into %1.", dvcs->name()), scratchArea, dest, job ? job->errorString() : QString()); 0183 return false; 0184 } 0185 0186 return true; // We're good 0187 } 0188 0189 /*! Setup version control for a new project defined by @p info. Use @p scratchArea for temporary files */ 0190 bool initializeCVCS(ICentralizedVersionControl* cvcs, const ApplicationInfo& info, QTemporaryDir& scratchArea) 0191 { 0192 Q_ASSERT(cvcs); 0193 0194 qCDebug(PLUGIN_APPWIZARD) << "Importing" << info.sourceLocation << "to" 0195 << info.repository.repositoryServer(); 0196 VcsJob* job = cvcs->import( info.importCommitMessage, QUrl::fromLocalFile(scratchArea.path()), info.repository); 0197 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded ) 0198 { 0199 vcsError(i18n("Could not import project"), scratchArea, QUrl::fromUserInput(info.repository.repositoryServer())); 0200 return false; 0201 } 0202 0203 qCDebug(PLUGIN_APPWIZARD) << "Checking out"; 0204 job = cvcs->createWorkingCopy( info.repository, info.location, IBasicVersionControl::Recursive); 0205 if (!job || !job->exec() || job->status() != VcsJob::JobSucceeded ) 0206 { 0207 vcsError(i18n("Could not checkout imported project"), scratchArea, QUrl::fromUserInput(info.repository.repositoryServer())); 0208 return false; 0209 } 0210 0211 return true; // initialization phase complete 0212 } 0213 0214 QString generateIdentifier( const QString& appname ) 0215 { 0216 QString tmp = appname; 0217 QRegExp re(QStringLiteral("[^a-zA-Z0-9_]")); 0218 return tmp.replace(re, QStringLiteral("_")); 0219 } 0220 0221 } // end anonymous namespace 0222 0223 QString AppWizardPlugin::createProject(const ApplicationInfo& info) 0224 { 0225 QFileInfo templateInfo(info.appTemplate); 0226 if (!templateInfo.exists()) { 0227 qCWarning(PLUGIN_APPWIZARD) << "Project app template does not exist:" << info.appTemplate; 0228 return QString(); 0229 } 0230 0231 QString templateName = templateInfo.baseName(); 0232 qCDebug(PLUGIN_APPWIZARD) << "Searching archive for template name:" << templateName; 0233 0234 QString templateArchive; 0235 const QStringList filters = {templateName + QStringLiteral(".*")}; 0236 const QStringList matchesPaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdevappwizard/templates/"), QStandardPaths::LocateDirectory); 0237 for (const QString& matchesPath : matchesPaths) { 0238 const QStringList files = QDir(matchesPath).entryList(filters); 0239 if(!files.isEmpty()) { 0240 templateArchive = matchesPath + files.first(); 0241 } 0242 } 0243 0244 if(templateArchive.isEmpty()) { 0245 qCWarning(PLUGIN_APPWIZARD) << "Template name does not exist in the template list"; 0246 return QString(); 0247 } 0248 0249 qCDebug(PLUGIN_APPWIZARD) << "Using template archive:" << templateArchive; 0250 0251 QUrl dest = info.location; 0252 0253 //prepare variable substitution hash 0254 m_variables.clear(); 0255 m_variables[QStringLiteral("APPNAME")] = info.name; 0256 m_variables[QStringLiteral("APPNAMEUC")] = generateIdentifier(info.name.toUpper()); 0257 m_variables[QStringLiteral("APPNAMELC")] = info.name.toLower(); 0258 m_variables[QStringLiteral("APPNAMEID")] = generateIdentifier(info.name); 0259 m_variables[QStringLiteral("PROJECTDIR")] = dest.toLocalFile(); 0260 // backwards compatibility 0261 m_variables[QStringLiteral("dest")] = m_variables[QStringLiteral("PROJECTDIR")]; 0262 m_variables[QStringLiteral("PROJECTDIRNAME")] = dest.fileName(); 0263 m_variables[QStringLiteral("VERSIONCONTROLPLUGIN")] = info.vcsPluginName; 0264 0265 KArchive* arch = nullptr; 0266 if( templateArchive.endsWith(QLatin1String(".zip")) ) 0267 { 0268 arch = new KZip(templateArchive); 0269 } 0270 else 0271 { 0272 arch = new KTar(templateArchive, QStringLiteral("application/x-bzip")); 0273 } 0274 if (arch->open(QIODevice::ReadOnly)) 0275 { 0276 QTemporaryDir tmpdir; 0277 QString unpackDir = tmpdir.path(); //the default value for all Centralized VCS 0278 IPlugin* plugin = core()->pluginController()->loadPlugin( info.vcsPluginName ); 0279 if( info.vcsPluginName.isEmpty() || ( plugin && plugin->extension<KDevelop::IDistributedVersionControl>() ) ) 0280 { 0281 if( !QFileInfo::exists( dest.toLocalFile() ) ) 0282 { 0283 QDir::root().mkpath( dest.toLocalFile() ); 0284 } 0285 unpackDir = dest.toLocalFile(); //in DVCS we unpack template directly to the project's directory 0286 } 0287 else 0288 { 0289 QUrl url = KIO::upUrl(dest); 0290 if(!QFileInfo::exists(url.toLocalFile())) { 0291 QDir::root().mkpath(url.toLocalFile()); 0292 } 0293 } 0294 0295 // estimate metadata files which should not be copied 0296 QStringList metaDataFileNames; 0297 0298 // try by same name 0299 const KArchiveEntry *templateEntry = 0300 arch->directory()->entry(templateName + QLatin1String(".kdevtemplate")); 0301 0302 // but could be different name, if e.g. downloaded, so make a guess 0303 if (!templateEntry || !templateEntry->isFile()) { 0304 const auto& entries = arch->directory()->entries(); 0305 for (const auto& entryName : entries) { 0306 if (entryName.endsWith(QLatin1String(".kdevtemplate"))) { 0307 templateEntry = arch->directory()->entry(entryName); 0308 break; 0309 } 0310 } 0311 } 0312 0313 if (templateEntry && templateEntry->isFile()) { 0314 metaDataFileNames << templateEntry->name(); 0315 0316 // check if a preview file is to be ignored 0317 const auto *templateFile = static_cast<const KArchiveFile*>(templateEntry); 0318 QTemporaryDir temporaryDir; 0319 templateFile->copyTo(temporaryDir.path()); 0320 0321 KConfig config(temporaryDir.path() + QLatin1Char('/') + templateEntry->name()); 0322 KConfigGroup group(&config, "General"); 0323 if (group.hasKey("Icon")) { 0324 const KArchiveEntry* iconEntry = arch->directory()->entry(group.readEntry("Icon")); 0325 if (iconEntry && iconEntry->isFile()) { 0326 metaDataFileNames << iconEntry->name(); 0327 } 0328 } 0329 } 0330 0331 if (!unpackArchive(arch->directory(), unpackDir, metaDataFileNames)) { 0332 QString errorMsg = i18n("Could not create new project"); 0333 vcsError(errorMsg, tmpdir, QUrl::fromLocalFile(unpackDir)); 0334 return QString(); 0335 } 0336 0337 if( !info.vcsPluginName.isEmpty() ) 0338 { 0339 if (!plugin) 0340 { 0341 // Red Alert, serious program corruption. 0342 // This should never happen, the vcs dialog presented a list of vcs 0343 // systems and now the chosen system doesn't exist anymore?? 0344 tmpdir.remove(); 0345 return QString(); 0346 } 0347 0348 IDistributedVersionControl* dvcs = toDVCS(plugin); 0349 ICentralizedVersionControl* cvcs = toCVCS(plugin); 0350 bool success = false; 0351 if (dvcs) 0352 { 0353 success = initializeDVCS(dvcs, info, tmpdir); 0354 } 0355 else if (cvcs) 0356 { 0357 success = initializeCVCS(cvcs, info, tmpdir); 0358 } 0359 else 0360 { 0361 if (KMessageBox::Continue == 0362 KMessageBox::warningContinueCancel(nullptr, 0363 QStringLiteral("Failed to initialize version control system, " 0364 "plugin is neither VCS nor DVCS."))) 0365 success = true; 0366 } 0367 if (!success) return QString(); 0368 } 0369 tmpdir.remove(); 0370 }else 0371 { 0372 qCDebug(PLUGIN_APPWIZARD) << "failed to open template archive"; 0373 return QString(); 0374 } 0375 0376 QString projectFileName = QDir::cleanPath(dest.toLocalFile() + QLatin1Char('/') + info.name + QLatin1String(".kdev4")); 0377 0378 // Loop through the new project directory and try to detect the first .kdev4 file. 0379 // If one is found this file will be used. So .kdev4 file can be stored in any subdirectory and the 0380 // project templates can be more complex. 0381 QDirIterator it(QDir::cleanPath( dest.toLocalFile()), QStringList() << QStringLiteral("*.kdev4"), QDir::NoFilter, QDirIterator::Subdirectories); 0382 if(it.hasNext() == true) 0383 { 0384 projectFileName = it.next(); 0385 } 0386 0387 qCDebug(PLUGIN_APPWIZARD) << "Returning" << projectFileName << QFileInfo::exists( projectFileName ) ; 0388 0389 const QFileInfo projectFileInfo(projectFileName); 0390 if (!projectFileInfo.exists()) { 0391 qCDebug(PLUGIN_APPWIZARD) << "creating .kdev4 file"; 0392 KSharedConfigPtr cfg = KSharedConfig::openConfig( projectFileName, KConfig::SimpleConfig ); 0393 KConfigGroup project = cfg->group( "Project" ); 0394 project.writeEntry( "Name", info.name ); 0395 QString manager = QStringLiteral("KDevGenericManager"); 0396 0397 QDir d( dest.toLocalFile() ); 0398 const auto data = ICore::self()->pluginController()->queryExtensionPlugins(QStringLiteral("org.kdevelop.IProjectFileManager")); 0399 for (const KPluginMetaData& info : data) { 0400 const auto filter = info.value(QStringLiteral("X-KDevelop-ProjectFilesFilter"), QStringList()); 0401 if (!filter.isEmpty()) { 0402 if (!d.entryList(filter).isEmpty()) { 0403 manager = info.pluginId(); 0404 break; 0405 } 0406 } 0407 } 0408 project.writeEntry( "Manager", manager ); 0409 project.sync(); 0410 cfg->sync(); 0411 KConfigGroup project2 = cfg->group( "Project" ); 0412 qCDebug(PLUGIN_APPWIZARD) << "kdev4 file contents:" << project2.readEntry("Name", "") << project2.readEntry("Manager", "" ); 0413 } 0414 0415 // create developer .kde4 file 0416 const QString developerProjectFileName = projectFileInfo.canonicalPath() + QLatin1String("/.kdev4/") + projectFileInfo.fileName(); 0417 0418 qCDebug(PLUGIN_APPWIZARD) << "creating developer .kdev4 file:" << developerProjectFileName; 0419 KSharedConfigPtr developerCfg = KSharedConfig::openConfig(developerProjectFileName, KConfig::SimpleConfig); 0420 KConfigGroup developerProjectGroup = developerCfg->group("Project"); 0421 developerProjectGroup.writeEntry("VersionControlSupport", info.vcsPluginName); 0422 developerProjectGroup.sync(); 0423 0424 developerCfg->sync(); 0425 0426 return projectFileName; 0427 } 0428 0429 bool AppWizardPlugin::unpackArchive(const KArchiveDirectory* dir, const QString& dest, const QStringList& skipList) 0430 { 0431 qCDebug(PLUGIN_APPWIZARD) << "unpacking dir:" << dir->name() << "to" << dest; 0432 const QStringList entries = dir->entries(); 0433 qCDebug(PLUGIN_APPWIZARD) << "entries:" << entries.join(QLatin1Char(',')); 0434 0435 //This extra tempdir is needed just for the files that have special names, 0436 //which may contain macros also files contain content with macros. So the 0437 //easiest way to extract the files from the archive and then rename them 0438 //and replace the macros is to use a tempdir and copy the file (and 0439 //replacing while copying). This also allows one to easily remove all files, 0440 //by just unlinking the tempdir 0441 QTemporaryDir tdir; 0442 0443 bool ret = true; 0444 0445 for (const auto& entryName : entries) { 0446 if (skipList.contains(entryName)) { 0447 continue; 0448 } 0449 0450 const auto entry = dir->entry(entryName); 0451 if (entry->isDirectory()) { 0452 const auto* subdir = static_cast<const KArchiveDirectory*>(entry); 0453 const QString newdest = dest + QLatin1Char('/') + KMacroExpander::expandMacros(subdir->name(), m_variables); 0454 if( !QFileInfo::exists( newdest ) ) 0455 { 0456 QDir::root().mkdir( newdest ); 0457 } 0458 ret |= unpackArchive(subdir, newdest); 0459 } 0460 else if (entry->isFile()) { 0461 const auto* file = static_cast<const KArchiveFile*>(entry); 0462 file->copyTo(tdir.path()); 0463 const QString destName = dest + QLatin1Char('/') + file->name(); 0464 if (!copyFileAndExpandMacros(QDir::cleanPath(tdir.path() + QLatin1Char('/') + file->name()), 0465 KMacroExpander::expandMacros(destName, m_variables))) 0466 { 0467 KMessageBox::error(nullptr, i18n("The file %1 cannot be created.", dest)); 0468 return false; 0469 } 0470 } 0471 } 0472 tdir.remove(); 0473 return ret; 0474 } 0475 0476 bool AppWizardPlugin::copyFileAndExpandMacros(const QString &source, const QString &dest) 0477 { 0478 qCDebug(PLUGIN_APPWIZARD) << "copy:" << source << "to" << dest; 0479 QMimeDatabase db; 0480 QMimeType mime = db.mimeTypeForFile(source); 0481 if( !mime.inherits(QStringLiteral("text/plain")) ) 0482 { 0483 KIO::CopyJob* job = KIO::copy( QUrl::fromUserInput(source), QUrl::fromUserInput(dest), KIO::HideProgressInfo ); 0484 if( !job->exec() ) 0485 { 0486 return false; 0487 } 0488 return true; 0489 } else 0490 { 0491 QFile inputFile(source); 0492 QFile outputFile(dest); 0493 0494 0495 if (inputFile.open(QFile::ReadOnly) && outputFile.open(QFile::WriteOnly)) 0496 { 0497 QTextStream input(&inputFile); 0498 input.setCodec(QTextCodec::codecForName("UTF-8")); 0499 QTextStream output(&outputFile); 0500 output.setCodec(QTextCodec::codecForName("UTF-8")); 0501 while(!input.atEnd()) 0502 { 0503 QString line = input.readLine(); 0504 output << KMacroExpander::expandMacros(line, m_variables) << "\n"; 0505 } 0506 #ifndef Q_OS_WIN 0507 // Preserve file mode... 0508 QT_STATBUF statBuf; 0509 QT_FSTAT(inputFile.handle(), &statBuf); 0510 // Unix only, won't work in Windows, maybe KIO::chmod could be used 0511 ::fchmod(outputFile.handle(), statBuf.st_mode); 0512 #endif 0513 return true; 0514 } 0515 else 0516 { 0517 inputFile.close(); 0518 outputFile.close(); 0519 return false; 0520 } 0521 } 0522 } 0523 KDevelop::ContextMenuExtension AppWizardPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent) 0524 { 0525 Q_UNUSED(parent); 0526 KDevelop::ContextMenuExtension ext; 0527 if ( context->type() != KDevelop::Context::ProjectItemContext || !static_cast<KDevelop::ProjectItemContext*>(context)->items().isEmpty() ) { 0528 return ext; 0529 } 0530 ext.addAction(KDevelop::ContextMenuExtension::ProjectGroup, m_newFromTemplate); 0531 return ext; 0532 } 0533 0534 ProjectTemplatesModel* AppWizardPlugin::model() const 0535 { 0536 if(!m_templatesModel) { 0537 auto* self = const_cast<AppWizardPlugin*>(this); 0538 m_templatesModel = new ProjectTemplatesModel(self); 0539 } 0540 return m_templatesModel; 0541 } 0542 0543 QAbstractItemModel* AppWizardPlugin::templatesModel() const 0544 { 0545 return model(); 0546 } 0547 0548 QString AppWizardPlugin::knsConfigurationFile() const 0549 { 0550 return QStringLiteral("kdevappwizard.knsrc"); 0551 } 0552 0553 QStringList AppWizardPlugin::supportedMimeTypes() const 0554 { 0555 const QStringList types{ 0556 QStringLiteral("application/x-desktop"), 0557 QStringLiteral("application/x-bzip-compressed-tar"), 0558 QStringLiteral("application/zip"), 0559 }; 0560 return types; 0561 } 0562 0563 QIcon AppWizardPlugin::icon() const 0564 { 0565 return QIcon::fromTheme(QStringLiteral("project-development-new-template")); 0566 } 0567 0568 QString AppWizardPlugin::name() const 0569 { 0570 return i18n("Project Templates"); 0571 } 0572 0573 void AppWizardPlugin::loadTemplate(const QString& fileName) 0574 { 0575 model()->loadTemplateFile(fileName); 0576 } 0577 0578 void AppWizardPlugin::reload() 0579 { 0580 model()->refresh(); 0581 } 0582 0583 0584 #include "appwizardplugin.moc" 0585 #include "moc_appwizardplugin.cpp"