kde-extraapps/kdevplatform/plugins/appwizard/projectselectionpage.cpp
2015-07-26 14:23:17 +03:00

337 lines
11 KiB
C++

/***************************************************************************
* Copyright 2007 Alexander Dymo <adymo@kdevelop.org> *
* Copyright 2011 Aleix Pol Gonzalez <aleixpol@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "projectselectionpage.h"
#include <QDir>
#include <klineedit.h>
#include <kcomponentdata.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <interfaces/icore.h>
#include <interfaces/iprojectcontroller.h>
#include <util/multilevellistview.h>
#include "ui_projectselectionpage.h"
#include "projecttemplatesmodel.h"
#include <KColorScheme>
#include <KFileDialog>
#include <KTar>
#include <KZip>
ProjectSelectionPage::ProjectSelectionPage(ProjectTemplatesModel *templatesModel, AppWizardDialog *wizardDialog)
: AppWizardPageWidget(wizardDialog), m_templatesModel(templatesModel)
{
ui = new Ui::ProjectSelectionPage();
ui->setupUi(this);
setContentsMargins(0,0,0,0);
ui->descriptionContent->setBackgroundRole(QPalette::Base);
ui->descriptionContent->setForegroundRole(QPalette::Text);
ui->locationUrl->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
ui->locationUrl->setUrl(KDevelop::ICore::self()->projectController()->projectsBaseDirectory());
ui->locationValidLabel->setText(QString(" "));
connect( ui->locationUrl->lineEdit(), SIGNAL(textEdited(QString)),
this, SLOT(urlEdited()));
connect( ui->locationUrl, SIGNAL(urlSelected(KUrl)),
this, SLOT(urlEdited()));
connect( ui->appNameEdit, SIGNAL(textEdited(QString)),
this, SLOT(nameChanged()) );
m_listView = new KDevelop::MultiLevelListView(this);
m_listView->setLevels(2);
m_listView->setHeaderLabels(QStringList() << i18n("Category") << i18n("Project Type"));
m_listView->setModel(templatesModel);
m_listView->setLastModelsFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
m_listView->setContentsMargins(0, 0, 0, 0);
connect (m_listView, SIGNAL(currentIndexChanged(QModelIndex,QModelIndex)), SLOT(typeChanged(QModelIndex)));
ui->gridLayout->addWidget(m_listView, 0, 0, 1, 1);
typeChanged(m_listView->currentIndex());
connect( ui->templateType, SIGNAL(currentIndexChanged(int)),
this, SLOT(templateChanged(int)) );
KPushButton* loadButton = new KPushButton(m_listView);
loadButton->setText(i18n("Load Template From File"));
loadButton->setIcon(KIcon("application-x-archive"));
connect (loadButton, SIGNAL(clicked(bool)), this, SLOT(loadFileClicked()));
m_listView->addWidget(0, loadButton);
m_wizardDialog = wizardDialog;
}
void ProjectSelectionPage::nameChanged()
{
validateData();
emit locationChanged( location() );
}
ProjectSelectionPage::~ProjectSelectionPage()
{
delete ui;
}
void ProjectSelectionPage::typeChanged(const QModelIndex& idx)
{
if (!idx.model())
{
kDebug() << "Index with no model";
return;
}
int children = idx.model()->rowCount(idx);
ui->templateType->setVisible(children);
ui->templateType->setEnabled(children > 1);
if (children) {
ui->templateType->setModel(m_templatesModel);
ui->templateType->setRootModelIndex(idx);
ui->templateType->setCurrentIndex(0);
itemChanged(idx.child(0, 0));
} else {
itemChanged(idx);
}
}
void ProjectSelectionPage::templateChanged(int current)
{
QModelIndex idx=m_templatesModel->index(current, 0, ui->templateType->rootModelIndex());
itemChanged(idx);
}
void ProjectSelectionPage::itemChanged( const QModelIndex& current)
{
QString picPath = current.data( KDevelop::TemplatesModel::IconNameRole ).toString();
if( picPath.isEmpty() ) {
KIcon icon("kdevelop");
ui->icon->setPixmap(icon.pixmap(128, 128));
ui->icon->setFixedHeight(128);
} else {
QPixmap pixmap( picPath );
ui->icon->setPixmap( pixmap );
ui->icon->setFixedHeight( pixmap.height() );
}
// header name is either from this index directly or the parents if we show the combo box
const QVariant headerData = ui->templateType->isVisible()
? current.parent().data()
: current.data();
ui->header->setText(QString("<h1>%1</h1>").arg(headerData.toString().trimmed()));
ui->description->setText(current.data(KDevelop::TemplatesModel::CommentRole).toString());
validateData();
ui->propertiesBox->setEnabled(true);
}
QString ProjectSelectionPage::selectedTemplate()
{
QStandardItem *item = getCurrentItem();
if (item)
return item->data().toString();
else
return "";
}
KUrl ProjectSelectionPage::location()
{
KUrl tUrl = ui->locationUrl->url();
tUrl.addPath( encodedAppName() );
return tUrl;
}
QString ProjectSelectionPage::appName()
{
return ui->appNameEdit->text();
}
void ProjectSelectionPage::urlEdited()
{
validateData();
emit locationChanged( location() );
}
void setForeground(QLabel* label, KColorScheme::ForegroundRole role)
{
QPalette p = label->palette();
KColorScheme::adjustForeground(p, role, label->foregroundRole(), KColorScheme::Window);
label->setPalette(p);
}
void ProjectSelectionPage::validateData()
{
KUrl url = ui->locationUrl->url();
if( !url.isLocalFile() || url.isEmpty() )
{
ui->locationValidLabel->setText( i18n("Invalid location") );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
if( appName().isEmpty() )
{
ui->locationValidLabel->setText( i18n("Empty project name") );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
if( !appName().isEmpty() )
{
QString appname = appName();
QString templatefile = m_wizardDialog->appInfo().appTemplate;
// Read template file
KConfig config(templatefile);
KConfigGroup configgroup(&config, "General");
QString pattern = configgroup.readEntry( "ValidProjectName" , "^[a-zA-Z][a-zA-Z0-9_]+$" );
// Validation
int pos = 0;
QRegExp regex( pattern );
QRegExpValidator validator( regex );
if( validator.validate(appname, pos) == QValidator::Invalid )
{
ui->locationValidLabel->setText( i18n("Invalid project name") );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
}
QDir tDir(url.toLocalFile( KUrl::RemoveTrailingSlash ));
while (!tDir.exists() && !tDir.isRoot()) {
if (!tDir.cdUp()) {
break;
}
}
if (tDir.exists())
{
QFileInfo tFileInfo(tDir.absolutePath());
if (!tFileInfo.isWritable() || !tFileInfo.isExecutable())
{
ui->locationValidLabel->setText( i18n("Unable to create subdirectories, "
"missing permissions on: %1", tDir.absolutePath()) );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
}
QStandardItem* item = getCurrentItem();
if( item && !item->hasChildren() )
{
ui->locationValidLabel->setText( QString(" ") );
setForeground(ui->locationValidLabel, KColorScheme::NormalText);
emit valid();
} else
{
ui->locationValidLabel->setText( i18n("Invalid project template, please choose a leaf item") );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
// Check for non-empty target directory.
url.addPath( encodedAppName() );
QFileInfo fi( url.toLocalFile( KUrl::RemoveTrailingSlash ) );
if( fi.exists() && fi.isDir() )
{
if( !QDir( fi.absoluteFilePath()).entryList( QDir::NoDotAndDotDot | QDir::AllEntries ).isEmpty() )
{
ui->locationValidLabel->setText( i18n("Path already exists and contains files") );
setForeground(ui->locationValidLabel, KColorScheme::NegativeText);
emit invalid();
return;
}
}
}
QByteArray ProjectSelectionPage::encodedAppName()
{
// : < > * ? / \ | " are invalid on windows
QByteArray tEncodedName = appName().toUtf8();
for (int i = 0; i < tEncodedName.size(); ++i)
{
QChar tChar(tEncodedName.at( i ));
if (tChar.isDigit() || tChar.isSpace() || tChar.isLetter() || tChar == '%')
continue;
QByteArray tReplace = QUrl::toPercentEncoding( tChar );
tEncodedName.replace( tEncodedName.at( i ) ,tReplace );
i = i + tReplace.size() - 1;
}
return tEncodedName;
}
QStandardItem* ProjectSelectionPage::getCurrentItem() const
{
QStandardItem* item = m_templatesModel->itemFromIndex( m_listView->currentIndex() );
if ( item && item->hasChildren() )
{
const int currect = ui->templateType->currentIndex();
const QModelIndex idx = m_templatesModel->index( currect, 0, ui->templateType->rootModelIndex() );
item = m_templatesModel->itemFromIndex(idx);
}
return item;
}
bool ProjectSelectionPage::shouldContinue()
{
QFileInfo fi(location().toLocalFile(KUrl::RemoveTrailingSlash));
if (fi.exists() && fi.isDir())
{
if (!QDir(fi.absoluteFilePath()).entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty())
{
int res = KMessageBox::questionYesNo(this, i18n("The specified path already exists and contains files. "
"Are you sure you want to proceed?"));
return res == KMessageBox::Yes;
}
}
return true;
}
void ProjectSelectionPage::loadFileClicked()
{
QString filter = "application/x-desktop application/x-bzip-compressed-tar application/zip";
QString fileName = KFileDialog::getOpenFileName(KUrl("kfiledialog:///kdevapptemplate"), filter, this);
if (!fileName.isEmpty())
{
QString destination = m_templatesModel->loadTemplateFile(fileName);
QModelIndexList indexes = m_templatesModel->templateIndexes(destination);
if (indexes.size() > 2)
{
m_listView->setCurrentIndex(indexes.at(1));
ui->templateType->setCurrentIndex(indexes.at(2).row());
}
}
}
void ProjectSelectionPage::setCurrentTemplate (const QString& fileName)
{
QModelIndexList indexes = m_templatesModel->templateIndexes(fileName);
if (indexes.size() > 1)
{
m_listView->setCurrentIndex(indexes.at(1));
}
if (indexes.size() > 2)
{
ui->templateType->setCurrentIndex(indexes.at(2).row());
}
}
#include "moc_projectselectionpage.cpp"