work save: new project

This commit is contained in:
royqh1979@gmail.com 2021-09-16 23:51:05 +08:00
parent 02b3d43e5d
commit f8be0d62c7
28 changed files with 395 additions and 45 deletions

View File

@ -149,10 +149,13 @@ Editor::~Editor() {
this->setParent(nullptr);
}
void Editor::loadFile() {
void Editor::loadFile(const QString& filename) {
if (!filename.isEmpty()) {
mFilename = filename;
}
QFile file(mFilename);
this->lines()->LoadFromFile(file,mEncodingOption,mFileEncoding);
this->setModified(false);
//this->setModified(false);
updateCaption();
pMainWindow->updateForEncodingInfo();
switch(getFileType(mFilename)) {
@ -1680,6 +1683,20 @@ void Editor::reparse()
parseFile(mParser,mFilename,mInProject);
}
void Editor::insertString(const QString &value, bool moveCursor)
{
beginUpdate();
auto action = finally([this]{
endUpdate();
});
BufferCoord oldCursorPos = caretXY();
setSelText(value);
if (!moveCursor) {
setCaretXY(oldCursorPos);
}
}
void Editor::showCompletion(bool autoComplete)
{
if (!pSettings->codeCompletion().enabled())

View File

@ -104,7 +104,7 @@ public:
bool inProject() const noexcept;
bool isNew() const noexcept;
void loadFile();
void loadFile(const QString& filename = "");
void saveFile(const QString& filename);
void convertToEncoding(const QByteArray& encoding);
bool save(bool force=false, bool reparse=true);
@ -143,6 +143,7 @@ public:
void gotoDeclaration(const BufferCoord& pos);
void gotoDefinition(const BufferCoord& pos);
void reparse();
void insertString(const QString& value, bool moveCursor);
const PCppParser &parser();

View File

@ -454,5 +454,18 @@
<file>images/editor/currentline.png</file>
<file>images/editor/syntaxerror.png</file>
<file>images/editor/syntaxwarning.png</file>
<file>images/associations/c.ico</file>
<file>images/associations/cpp.ico</file>
<file>images/associations/dev.ico</file>
<file>images/associations/devpackage.ico</file>
<file>images/associations/devpak.ico</file>
<file>images/associations/h.ico</file>
<file>images/associations/hpp.ico</file>
<file>images/associations/ide.ico</file>
<file>images/associations/IDE2.ico</file>
<file>images/associations/o.ico</file>
<file>images/associations/obj.ico</file>
<file>images/associations/rc.ico</file>
<file>images/associations/template.ico</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -10,6 +10,8 @@
#include "widgets/cpudialog.h"
#include "widgets/filepropertiesdialog.h"
#include "project.h"
#include "projecttemplate.h"
#include "widgets/newprojectdialog.h"
#include <QCloseEvent>
#include <QComboBox>
@ -87,6 +89,11 @@ MainWindow::MainWindow(QWidget *parent)
ui->tableIssues->setWarningColor(QColor("Orange"));
mMenuNew = new QMenu();
mMenuNew->setTitle(tr("New"));
mMenuNew->addAction(ui->actionNew);
mMenuNew->addAction(ui->actionNew_Project);
ui->menuFile->insertMenu(ui->actionOpen,mMenuNew);
mMenuEncoding = new QMenu();
mMenuEncoding->setTitle(tr("File Encoding"));
mMenuEncoding->addAction(ui->actionAuto_Detect);
@ -2881,3 +2888,78 @@ void MainWindow::on_actionProject_options_triggered()
dialog->exec();
}
void MainWindow::on_actionNew_Project_triggered()
{
NewProjectDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
// Take care of the currently opened project
QString s;
if (mProject) {
if (mProject->name().isEmpty())
s = mProject->filename();
else
s = mProject->name();
// Ask if the user wants to close the current one. If not, abort
if (QMessageBox::question(this,
tr("New project"),
tr("Close %1 and start new project?").arg(s),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes)==QMessageBox::Yes) {
closeProject(false);
} else
return;
}
//Create the project folder
QDir dir(dialog.getLocation());
if (!dir.exists()) {
if (QMessageBox::question(this,
tr("Folder not exist"),
tr("Folder '%1' doesn't exist. Create it now?").arg(dialog.getLocation()),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes) != QMessageBox::Yes) {
return;
}
if (!dir.mkpath(dialog.getLocation())) {
QMessageBox::critical(this,
tr("Can't create folder"),
tr("Failed to create folder '%1'.").arg(dialog.getLocation()),
QMessageBox::Yes);
return;
}
}
openCloseLeftPanel(true);
ui->tabInfos->setCornerWidget(ui->tabProject);
// if cbDefault.Checked then
// devData.DefCpp := rbCpp.Checked;
s = includeTrailingPathDelimiter(dialog.getLocation())
+ dialog.getProjectName() + "." + DEV_PROJECT_EXT;
if (fileExists(s)) {
QString saveName = QFileDialog::getSaveFileName(
this,
tr("Save new project as"),
dialog.getLocation(),
tr("Red panda Dev-C++ project file (*.dev)"));
if (!saveName.isEmpty()) {
s = saveName;
}
}
// Create an empty project
mProject = std::make_shared<Project>(s,dialog.getProjectName());
if (!mProject->assignTemplate(dialog.getTemplate())) {
mProject = nullptr;
QMessageBox::critical(this,
tr("New project fail"),
tr("Can't assign project template"),
QMessageBox::Ok);
}
mProject->saveAll();
}
}

View File

@ -308,6 +308,8 @@ private slots:
void on_actionProject_options_triggered();
void on_actionNew_Project_triggered();
private:
Ui::MainWindow *ui;
EditorList *mEditorList;
@ -317,6 +319,7 @@ private:
QMenu *mMenuEncoding;
QMenu *mMenuEncodingList;
QMenu *mMenuRecentFiles;
QMenu *mMenuNew;
QComboBox *mCompilerSet;
CompilerManager *mCompilerManager;
Debugger *mDebugger;

View File

@ -780,7 +780,6 @@
<property name="title">
<string>File</string>
</property>
<addaction name="actionNew"/>
<addaction name="actionOpen"/>
<addaction name="separator"/>
<addaction name="actionSave"/>
@ -992,7 +991,10 @@
</iconset>
</property>
<property name="text">
<string>New</string>
<string>New File</string>
</property>
<property name="toolTip">
<string>New File</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
@ -1621,6 +1623,16 @@
<string>Project options</string>
</property>
</action>
<action name="actionNew_Project">
<property name="icon">
<iconset>
<normalon>:/icons/images/newlook24/049-newproj.png</normalon>
</iconset>
</property>
<property name="text">
<string>New Project...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -7,6 +7,7 @@
#include <parser/cppparser.h>
#include "utils.h"
#include "platform.h"
#include "projecttemplate.h"
#include <QDir>
#include <QFileDialog>
@ -209,7 +210,7 @@ PFolderNode Project::makeProjectNode()
return node;
}
int Project::newUnit(PFolderNode parentNode, const QString customFileName)
PProjectUnit Project::newUnit(PFolderNode parentNode, const QString& customFileName)
{
PProjectUnit newUnit = std::make_shared<ProjectUnit>(this);
@ -231,7 +232,7 @@ int Project::newUnit(PFolderNode parentNode, const QString customFileName)
s = dir.absoluteFilePath(customFileName);
}
// Add
int result = mUnits.count();
int count = mUnits.count();
mUnits.append(newUnit);
// Set all properties
@ -241,7 +242,7 @@ int Project::newUnit(PFolderNode parentNode, const QString customFileName)
newUnit->setFolder(getFolderPath(parentNode));
newUnit->setNode(makeNewFileNode(extractFileName(newUnit->fileName()),
false, parentNode));
newUnit->node()->unitIndex = result;
newUnit->node()->unitIndex = count;
//parentNode.Expand(True);
newUnit->setCompile(true);
newUnit->setCompileCpp(mOptions.useGPP);
@ -250,7 +251,7 @@ int Project::newUnit(PFolderNode parentNode, const QString customFileName)
newUnit->setOverrideBuildCmd(false);
newUnit->setBuildCmd("");
newUnit->setModified(true);
return result;
return newUnit;
}
Editor *Project::openUnit(int index)
@ -575,6 +576,59 @@ void Project::updateNodeIndexes()
mUnits[idx]->node()->unitIndex = idx;
}
bool Project::assignTemplate(const std::shared_ptr<ProjectTemplate> aTemplate)
{
if (!aTemplate) {
return true;
}
mOptions = aTemplate->options();
// Copy icon to project directory
if (!mOptions.icon.isEmpty()) {
QString originIcon = QDir(pSettings->dirs().templateDir()).absoluteFilePath(mOptions.icon);
if (fileExists(originIcon)) {
QString destIcon = changeFileExt(mFilename,".ico");
QFile::copy(originIcon,destIcon);
mOptions.icon = destIcon;
} else {
mOptions.icon = "";
}
}
// Add list of files
if (aTemplate->version() > 0) {
for (int i=0;i<aTemplate->unitCount();i++) {
// Pick file contents
PTemplateUnit templateUnit = aTemplate->unit(i);
QString s;
PProjectUnit unit;
if (aTemplate->options().useGPP) {
s = templateUnit->CppText;
unit = newUnit(mNode,templateUnit->CppName);
} else {
s = templateUnit->CText;
unit = newUnit(mNode,templateUnit->CName);
}
Editor * editor = pMainWindow->editorList()->newEditor(
unit->fileName(),
unit->encoding(),
true,
true);
QString s2 = QDir(pSettings->dirs().templateDir()).absoluteFilePath(s);
if (QFile(s2).exists()) {
editor->loadFile(s2);
} else {
s.replace("#13#10","\r\n");
editor->insertString(s,false);
}
editor->save(true,false);
editor->activate();
}
}
return true;
}
void Project::saveOptions()
{
SimpleIni ini;

View File

@ -96,6 +96,7 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
};
class ProjectTemplate;
class Project : public QObject
{
Q_OBJECT
@ -132,8 +133,8 @@ public:
void loadUnitLayout(Editor *e, int index); // load single [UnitX] cursor positions
PFolderNode makeNewFileNode(const QString& s, bool isFolder, PFolderNode newParent);
PFolderNode makeProjectNode();
int newUnit(PFolderNode parentNode,
const QString customFileName);
PProjectUnit newUnit(PFolderNode parentNode,
const QString& customFileName);
Editor* openUnit(int index);
void rebuildNodes();
bool removeEditor(int index, bool doClose);
@ -152,7 +153,7 @@ public:
void updateNodeIndexes();
//void showOptions();
// bool assignTemplate(const QString& aFileName, const PTemplate& aTemplate);
bool assignTemplate(const std::shared_ptr<ProjectTemplate> aTemplate);
//void saveToLog();
std::shared_ptr<CppParser> cppParser();

View File

@ -11,6 +11,7 @@ ProjectTemplate::ProjectTemplate(QObject *parent) : QObject(parent)
int ProjectTemplate::unitCount()
{
if (!mIni || mVersion<=0)
return 0;
return mIni->GetLongValue("Project","UnitCount",0);
}
@ -48,7 +49,7 @@ int ProjectTemplate::addUnit()
if (!mIni || mVersion<=0)
return -1;
int count = unitCount() +1;
QByteArray section = toByteArray(QString("Unit%1").arg(count));
QByteArray section = toByteArray(QString("Unit%1").arg(count-1));
mIni->SetValue(section, "C", "");
mIni->SetValue(section, "Cpp", "");
mIni->SetLongValue("Project", "UnitCount", count);
@ -188,3 +189,8 @@ void ProjectTemplate::setOptions(const ProjectOptions &newOptions)
mOptions = newOptions;
}
int ProjectTemplate::version() const
{
return mVersion;
}

View File

@ -43,6 +43,8 @@ public:
const ProjectOptions &options() const;
void setOptions(const ProjectOptions &newOptions);
int version() const;
private:
QString mFileName;
ProjectOptions mOptions;

View File

@ -70,7 +70,7 @@ void SystemConsts::addDefaultFileFilter(const QString &name, const QString &file
addFileFilter(mDefaultFileFilters,name,fileExtensions);
}
void SystemConsts::addFileFilter(QStringList filters, const QString &name, const QString &fileExtensions)
void SystemConsts::addFileFilter(QStringList& filters, const QString &name, const QString &fileExtensions)
{
filters.append(name+ " (" + fileExtensions+")");
}

View File

@ -67,7 +67,7 @@ public:
const QStringList &codecNames() const;
private:
void addFileFilter(QStringList filters, const QString& name, const QString& fileExtensions);
void addFileFilter(QStringList& filters, const QString& name, const QString& fileExtensions);
QStringList mDefaultFileFilters;
QStringList mIconFileFilters;
QStringList mCodecNames;

View File

@ -5,6 +5,8 @@
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QPushButton>
NewProjectDialog::NewProjectDialog(QWidget *parent) :
QDialog(parent),
@ -13,6 +15,30 @@ NewProjectDialog::NewProjectDialog(QWidget *parent) :
ui->setupUi(this);
mTemplatesTabBar = new QTabBar(this);
ui->verticalLayout->insertWidget(0,mTemplatesTabBar);
readTemplateDir();
int i=0;
QString projectName;
QString location;
while (true) {
i++;
projectName = tr("Project %1").arg(i);
location = includeTrailingPathDelimiter(pSettings->dirs().projectDir()) + projectName;
if (!QDir(location).exists())
break;
}
ui->txtProjectName->setText(projectName);
ui->txtLocation->setText(location);
connect(mTemplatesTabBar,
&QTabBar::currentChanged,
this,
&NewProjectDialog::updateView
);
connect(ui->txtProjectName,
&QLineEdit::textChanged,
this,
&NewProjectDialog::updateProjectLocation);
}
NewProjectDialog::~NewProjectDialog()
@ -20,6 +46,40 @@ NewProjectDialog::~NewProjectDialog()
delete ui;
}
PProjectTemplate NewProjectDialog::getTemplate()
{
QListWidgetItem * item = ui->lstTemplates->currentItem();
if (!item)
return PProjectTemplate();
int index = item->data(Qt::UserRole).toInt();
return mTemplates[index];
}
QString NewProjectDialog::getLocation()
{
return ui->txtLocation->text();
}
QString NewProjectDialog::getProjectName()
{
return ui->txtProjectName->text();
}
bool NewProjectDialog::isCProject()
{
return ui->rdCProject->isChecked();
}
bool NewProjectDialog::isCppProject()
{
return ui->rdCppProject->isChecked();
}
bool NewProjectDialog::makeProjectDefault()
{
return ui->chkMakeDefault->isChecked();
}
void NewProjectDialog::addTemplate(const QString &filename)
{
if (!QFile(filename).exists())
@ -40,48 +100,125 @@ void NewProjectDialog::readTemplateDir()
addTemplate(fileInfo.absoluteFilePath());
}
}
rebuildTabs();
updateView();
}
void NewProjectDialog::updateView()
void NewProjectDialog::rebuildTabs()
{
while (mTemplatesTabBar->count()>0) {
mTemplatesTabBar->removeTab(0);
}
QMap<QString,int> categories;
mCategories.clear();
foreach (const PProjectTemplate& t, mTemplates) {
QString category = t->category();
if (category.isEmpty())
category = tr("Default");
// Add a page for each unique category
int tabIndex = categories.value(category,-1);
int tabIndex = mCategories.value(category,-1);
if (tabIndex<0) {
tabIndex = mTemplatesTabBar->addTab(category);
categories.insert(category,tabIndex);
mCategories.insert(category,tabIndex);
}
}
mTemplatesTabBar->setCurrentIndex(0);
}
// Only add if we're viewing this category
if SameText(TemplateItem.Category, TabsMain.Tabs[TabsMain.TabIndex]) then begin
ListItem := ProjView.Items.Add;
ListItem.Caption := TemplateItem.Name;
ListItem.Data := pointer(I);
IconFileName := ValidateFile(TemplateItem.Icon, '', true);
if IconFileName <> '' then begin
// Add icon to central dump and tell ListItem to use it
IconItem := TIcon.Create;
try
IconItem.LoadFromFile(IconFileName); // ValidateFile prepends path
ListItem.ImageIndex := ImageList.AddIcon(IconItem);
if ListItem.ImageIndex = -1 then
ListItem.ImageIndex := 0;
finally
IconItem.Free;
end;
end else
ListItem.ImageIndex := 0; // don't use an icon
end;
void NewProjectDialog::updateView()
{
int index = std::max(0,mTemplatesTabBar->currentIndex());
if (index>=mTemplatesTabBar->count())
return;
ui->lstTemplates->clear();
for (int i=0;i<mTemplates.count();i++) {
const PProjectTemplate& t = mTemplates[i];
QString category = t->category();
if (category.isEmpty())
category = tr("Default");
QString tabText = mTemplatesTabBar->tabText(index);
if (category == tabText) {
QListWidgetItem * item;
QString iconFilename = QDir(pSettings->dirs().templateDir()).absoluteFilePath(t->icon());
QIcon icon(iconFilename);
if (icon.isNull()) {
//todo : use an default icon
item = new QListWidgetItem(
QIcon(":/icons/images/associations/template.ico"),
t->name());
} else {
item = new QListWidgetItem(
icon,
t->name());
}
item->setData(Qt::UserRole,i);
ui->lstTemplates->addItem(item);
}
}
}
void NewProjectDialog::updateProjectLocation()
{
ui->txtLocation->setText(
includeTrailingPathDelimiter(
extractFilePath(
ui->txtLocation->text()))
+ ui->txtProjectName->text()
);
QListWidgetItem * current = ui->lstTemplates->currentItem();
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
current && !ui->txtProjectName->text().isEmpty()
);
}
void NewProjectDialog::on_lstTemplates_itemDoubleClicked(QListWidgetItem *item)
{
if (item)
accept();
}
void NewProjectDialog::on_lstTemplates_currentItemChanged(QListWidgetItem *current, QListWidgetItem *)
{
if (current) {
int index = current->data(Qt::UserRole).toInt();
PProjectTemplate t = mTemplates[index];
ui->lblDescription->setText(t->description());
if (t->options().useGPP) {
ui->rdCppProject->setChecked(true);
} else {
ui->rdCProject->setChecked(true);
}
} else {
ui->lblDescription->setText("");
ui->rdCProject->setChecked(false);
ui->rdCppProject->setChecked(false);
ui->chkMakeDefault->setChecked(false);
}
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
current && !ui->txtProjectName->text().isEmpty()
);
}
void NewProjectDialog::on_btnBrowse_triggered(QAction *)
{
QString dirPath = ui->txtLocation->text();
if (!QDir(dirPath).exists()) {
dirPath = pSettings->dirs().projectDir();
}
QString dir = QFileDialog::getExistingDirectory(
this,
"Project directory",
dirPath
);
if (!dir.isEmpty()) {
ui->txtLocation->setText(dir);
QListWidgetItem * current = ui->lstTemplates->currentItem();
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
current && !ui->txtProjectName->text().isEmpty()
);
}
}

View File

@ -2,6 +2,7 @@
#define NEWPROJECTDIALOG_H
#include <QDialog>
#include <QListWidget>
#include <QTabBar>
#include "projecttemplate.h"
@ -16,14 +17,29 @@ class NewProjectDialog : public QDialog
public:
explicit NewProjectDialog(QWidget *parent = nullptr);
~NewProjectDialog();
PProjectTemplate getTemplate();
QString getLocation();
QString getProjectName();
bool isCProject();
bool isCppProject();
bool makeProjectDefault();
private slots:
void updateView();
void updateProjectLocation();
void on_lstTemplates_itemDoubleClicked(QListWidgetItem *item);
void on_lstTemplates_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void on_btnBrowse_triggered(QAction *arg1);
private:
void addTemplate(const QString& filename);
void readTemplateDir();
void updateView();
void rebuildTabs();
private:
Ui::NewProjectDialog *ui;
QList<PProjectTemplate> mTemplates;
QTabBar* mTemplatesTabBar;
QMap<QString,int> mCategories;
};
#endif // NEWPROJECTDIALOG_H

View File

@ -15,10 +15,16 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="lstTemplates">
<widget class="QListWidget" name="lstTemplates">
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
<property name="itemAlignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
@ -97,7 +103,7 @@
<widget class="QLineEdit" name="txtLocation"/>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="toolButton">
<widget class="QToolButton" name="btnBrowse">
<property name="text">
<string>...</string>
</property>
@ -109,7 +115,7 @@
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLineEdit" name="txtName"/>
<widget class="QLineEdit" name="txtProjectName"/>
</item>
</layout>
</widget>