RedPanda-CPP/RedPandaIDE/project.cpp

1696 lines
56 KiB
C++
Raw Normal View History

2021-09-05 23:45:05 +08:00
#include "project.h"
#include "editor.h"
#include "mainwindow.h"
2021-09-06 08:45:53 +08:00
#include "utils.h"
#include "systemconsts.h"
2021-09-07 16:49:35 +08:00
#include "editorlist.h"
#include <parser/cppparser.h>
#include "utils.h"
2021-09-06 08:45:53 +08:00
#include <QDir>
2021-09-09 00:15:12 +08:00
#include <QFileDialog>
2021-09-06 08:45:53 +08:00
#include <QFileInfo>
2021-09-06 12:58:29 +08:00
#include <QMessageBox>
2021-09-09 11:47:04 +08:00
#include "settings.h"
2021-09-05 23:45:05 +08:00
2021-09-11 09:21:44 +08:00
Project::Project(const QString &filename, const QString &name, QObject *parent) :
QObject(parent),
mModel(this)
2021-09-05 23:45:05 +08:00
{
2021-09-07 16:49:35 +08:00
mFilename = filename;
mIniFile = std::make_shared<QSettings>(filename,QSettings::IniFormat);
mParser = std::make_shared<CppParser>();
mParser->setOnGetFileStream(
std::bind(
&EditorList::getContentFromOpenedEditor,pMainWindow->editorList(),
std::placeholders::_1, std::placeholders::_2));
resetCppParser(mParser);
if (name == DEV_INTERNAL_OPEN)
open();
else {
mName = name;
mIniFile->beginGroup("Project");
mIniFile->setValue("filename", mFilename);
mIniFile->setValue("name", mName);
mIniFile->endGroup();
mNode = makeProjectNode();
}
2021-09-05 23:45:05 +08:00
}
2021-09-09 11:47:04 +08:00
QString Project::directory() const
2021-09-06 08:45:53 +08:00
{
QFileInfo fileInfo(mFilename);
return fileInfo.absolutePath();
}
2021-09-09 11:47:04 +08:00
QString Project::executable() const
2021-09-06 08:45:53 +08:00
{
QString exeFileName;
if (mOptions.overrideOutput && !mOptions.overridenOutput.isEmpty()) {
exeFileName = mOptions.overridenOutput;
} else {
switch(mOptions.type) {
case ProjectType::StaticLib:
2021-09-10 12:37:02 +08:00
exeFileName = changeFileExt(extractFileName(mFilename),STATIC_LIB_EXT);
2021-09-06 08:45:53 +08:00
break;
case ProjectType::DynamicLib:
2021-09-10 12:37:02 +08:00
exeFileName = changeFileExt(extractFileName(mFilename),DYNAMIC_LIB_EXT);
2021-09-06 08:45:53 +08:00
break;
default:
2021-09-10 12:37:02 +08:00
exeFileName = changeFileExt(extractFileName(mFilename),EXECUTABLE_EXT);
2021-09-06 08:45:53 +08:00
}
}
QString exePath;
if (!mOptions.exeOutput.isEmpty()) {
QDir baseDir(directory());
exePath = baseDir.filePath(mOptions.exeOutput);
} else {
exePath = directory();
}
QDir exeDir(exePath);
return exeDir.filePath(exeFileName);
}
QString Project::makeFileName()
{
2021-09-06 12:58:29 +08:00
if (mOptions.useCustomMakefile)
return mOptions.customMakefile;
2021-09-06 08:45:53 +08:00
else
2021-09-06 12:58:29 +08:00
return QDir(directory()).filePath(MAKEFILE_NAME);
}
2021-09-09 11:47:04 +08:00
bool Project::modified() const
2021-09-06 12:58:29 +08:00
{
// Project file modified? Done
if (mModified)
return true;// quick exit avoids loop over all units
// Otherwise, check all units
foreach (const PProjectUnit& unit, mUnits){
if (unit->modified())
return true;
}
return false;
}
void Project::open()
{
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-06 12:58:29 +08:00
QFile fileInfo(mFilename);
if (fileInfo.exists()
&& !fileInfo.isWritable()) {
if (QMessageBox::question(pMainWindow,
tr("Remove Readonly Attribute"),
tr("Project file '%1' is readonly.<br /> Remove the readonly attribute?")
.arg(mFilename),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes) == QMessageBox::Yes) {
fileInfo.setPermissions(
QFileDevice::WriteOwner
| QFileDevice::WriteGroup
| QFileDevice::WriteUser
);
}
}
loadOptions();
2021-09-07 00:32:16 +08:00
mNode = makeProjectNode();
2021-09-06 12:58:29 +08:00
checkProjectFileForUpdate();
2021-09-07 00:32:16 +08:00
mIniFile->beginGroup("Project");
int uCount = mIniFile->value("UnitCount",0).toInt();
mIniFile->endGroup();
2021-09-06 12:58:29 +08:00
//createFolderNodes;
QDir dir(directory());
for (int i=0;i<uCount;i++) {
PProjectUnit newUnit = std::make_shared<ProjectUnit>();
2021-09-07 00:32:16 +08:00
mIniFile->beginGroup(QString("Unit%1").arg(i));
newUnit->setFileName(dir.filePath(mIniFile->value("FileName","").toString()));
2021-09-06 12:58:29 +08:00
if (!QFileInfo(newUnit->fileName()).exists()) {
QMessageBox::critical(pMainWindow,
tr("File Not Found"),
tr("Project file '%1' can't be found!")
.arg(newUnit->fileName()),
QMessageBox::Ok);
newUnit->setModified(true);
} else {
2021-09-07 00:32:16 +08:00
newUnit->setFolder(mIniFile->value("Folder","").toString());
newUnit->setCompile(mIniFile->value("Compile", true).toBool());
2021-09-06 18:59:06 +08:00
newUnit->setCompileCpp(
2021-09-07 00:32:16 +08:00
mIniFile->value("CompileCpp",mOptions.useGPP).toBool());
newUnit->setLink(mIniFile->value("Link", true).toBool());
newUnit->setPriority(mIniFile->value("Priority", 1000).toInt());
newUnit->setOverrideBuildCmd(mIniFile->value("OverrideBuildCmd", false).toInt());
newUnit->setBuildCmd(mIniFile->value("BuildCmd", "").toString());
2021-09-10 23:41:38 +08:00
newUnit->setEncoding(mIniFile->value("FileEncoding",ENCODING_SYSTEM_DEFAULT).toByteArray());
2021-09-07 00:32:16 +08:00
newUnit->setEditor(nullptr);
newUnit->setNew(false);
newUnit->setParent(this);
2021-09-10 12:37:02 +08:00
newUnit->setNode(makeNewFileNode(extractFileName(newUnit->fileName()), false, folderNodeFromName(newUnit->folder())));
2021-09-07 00:32:16 +08:00
newUnit->node()->unitIndex = mUnits.count();
mUnits.append(newUnit);
}
mIniFile->endGroup();
}
rebuildNodes();
}
2021-09-06 18:59:06 +08:00
2021-09-07 00:32:16 +08:00
void Project::setFileName(const QString &value)
{
if (mFilename!=value) {
mIniFile->sync();
mIniFile.reset();
2021-09-10 23:41:38 +08:00
QFile::rename(mFilename,value);
2021-09-07 00:32:16 +08:00
mFilename = value;
setModified(true);
2021-09-10 21:37:52 +08:00
mIniFile = std::make_shared<QSettings>(mFilename, QSettings::IniFormat);
2021-09-07 00:32:16 +08:00
}
}
2021-09-06 12:58:29 +08:00
2021-09-07 00:32:16 +08:00
void Project::setModified(bool value)
{
QFile file(mFilename);
// only mark modified if *not* read-only
if (!file.exists()
|| (file.exists() && file.isWritable())) {
mModified=value;
2021-09-07 10:28:40 +08:00
emit modifyChanged(mModified);
2021-09-07 00:32:16 +08:00
}
2021-09-07 10:28:40 +08:00
}
2021-09-06 12:58:29 +08:00
2021-09-10 10:27:01 +08:00
PFolderNode Project::makeNewFileNode(const QString &s, bool isFolder, PFolderNode newParent)
{
PFolderNode node = std::make_shared<FolderNode>();
node->parent = newParent;
node->text = s;
2021-09-10 21:37:52 +08:00
if (newParent) {
node->level = newParent->level+1;
}
if (isFolder)
node->unitIndex = -1;
2021-09-10 10:27:01 +08:00
}
PFolderNode Project::makeProjectNode()
{
PFolderNode node = std::make_shared<FolderNode>();
node->text = mName;
2021-09-10 21:37:52 +08:00
node->level = 0;
2021-09-10 10:27:01 +08:00
}
2021-09-10 21:37:52 +08:00
int Project::newUnit(PFolderNode parentNode, const QString customFileName)
2021-09-10 12:37:02 +08:00
{
PProjectUnit newUnit = std::make_shared<ProjectUnit>();
// Select folder to add unit to
if (!parentNode)
parentNode = mNode; // project root node
if (parentNode->unitIndex>=0) { //it's a file
parentNode = mNode;
}
QString s;
QDir dir(directory());
// Find unused 'new' filename
if (customFileName.isEmpty()) {
do {
s = dir.absoluteFilePath(tr("untitled")+QString("%1").arg(getNewFileNumber()));
} while (fileExists(s));
} else {
s = dir.absoluteFilePath(customFileName);
}
// Add
int result = mUnits.count();
mUnits.append(newUnit);
// Set all properties
newUnit->setFileName(s);
newUnit->setNew(true);
newUnit->setEditor(nullptr);
newUnit->setFolder(getFolderPath(parentNode));
newUnit->setNode(makeNewFileNode(extractFileName(newUnit->fileName()),
false, parentNode));
newUnit->node()->unitIndex = result;
//parentNode.Expand(True);
newUnit->setCompile(true);
newUnit->setCompileCpp(mOptions.useGPP);
newUnit->setLink(true);
newUnit->setPriority(1000);
newUnit->setOverrideBuildCmd(false);
newUnit->setBuildCmd("");
newUnit->setModified(true);
return result;
}
Editor *Project::openUnit(int index)
{
if ((index < 0) || (index >= mUnits.count()))
return nullptr;
PProjectUnit unit = mUnits[index];
if (!unit->fileName().isEmpty()) {
QDir dir(directory());
QString fullPath = dir.absoluteFilePath(unit->fileName());
Editor * editor = pMainWindow->editorList()->getOpenedEditorByFilename(fullPath);
if (editor) {//already opened in the editors
editor->setInProject(true);
return editor;
}
2021-09-10 15:03:47 +08:00
QByteArray encoding;
2021-09-10 23:41:38 +08:00
encoding = mOptions.encoding.toLocal8Bit();
2021-09-10 15:03:47 +08:00
editor = pMainWindow->editorList()->newEditor(fullPath, encoding, true, false);
editor->setInProject(true);
unit->setEditor(editor);
unit->setEncoding(encoding);
loadUnitLayout(editor,index);
return editor;
}
}
void Project::rebuildNodes()
{
// Remember if folder nodes were expanded or collapsed
// Create a list of expanded folder nodes
// QStringList oldPaths := TStringList.Create;
// with MainForm.ProjectView do
// for idx := 0 to Items.Count - 1 do begin
// tempnode := Items[idx];
// if tempnode.Expanded and (tempnode.Data = Pointer(-1)) then // data=pointer(-1) - it's folder
// oldPaths.Add(GetFolderPath(tempnode));
// end;
2021-09-10 12:37:02 +08:00
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
2021-09-10 15:03:47 +08:00
// Delete everything
mNode->children.clear();
// Recreate everything
createFolderNodes();
for (int idx=0;idx<mUnits.count();idx++) {
mUnits[idx]->setNode(
makeNewFileNode(
extractRelativePath(filename(),mUnits[idx]->fileName()),
false,
folderNodeFromName(mUnits[idx]->folder())
)
);
mUnits[idx]->node()->unitIndex = idx;
2021-09-10 12:37:02 +08:00
}
2021-09-10 15:03:47 +08:00
// // expand nodes expanded before recreating the project tree
// fNode.Collapse(True);
// with MainForm.ProjectView do
// for idx := 0 to Items.Count - 1 do begin
// tempnode := Items[idx];
// if (tempnode.Data = Pointer(-1)) then //it's a folder
// if oldPaths.IndexOf(GetFolderPath(tempnode)) >= 0 then
// tempnode.Expand(False);
// end;
// FreeAndNil(oldPaths);
// fNode.Expand(False);
2021-09-11 09:21:44 +08:00
mModel.endUpdate();
2021-09-10 15:03:47 +08:00
emit nodesChanged();
2021-09-10 12:37:02 +08:00
}
2021-09-10 21:37:52 +08:00
bool Project::removeEditor(int index, bool doClose)
{
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-10 21:37:52 +08:00
if (index<0 || index>=mUnits.count())
return false;
PProjectUnit unit = mUnits[index];
// Attempt to close it
if (doClose && (unit->editor())) {
if (!pMainWindow->editorList()->closeEditor(unit->editor()))
return false;
}
//if not fUnits.GetItem(index).fNew then
mIniFile->remove("Unit"+QString("%1").arg(index+1));
PFolderNode node = unit->node();
PFolderNode parent = node->parent.lock();
if (parent) {
parent->children.removeAll(node);
}
mUnits.removeAt(index);
updateNodeIndexes();
setModified(true);
return true;
}
bool Project::removeFolder(PFolderNode node)
{
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-10 21:37:52 +08:00
// Sanity check
if (!node)
return false;
// Check if this is actually a folder
if (node->unitIndex>=0 || node->level<1)
return false;
// Let this function call itself
removeFolderRecurse(node);
// Update list of folders (sets modified)
updateFolders();
return true;
}
void Project::saveAll()
{
if (!saveUnits())
return;
saveOptions(); // update other data, and save to disk
saveLayout(); // save current opened files, and which is "active".
// We have saved everything to disk, so mark unmodified
setModified(false);
}
void Project::saveLayout()
{
QString s = changeFileExt(mFilename, "layout");
QSettings layIni(mFilename,QSettings::IniFormat);
QStringList sl;
// Write list of open project files
for (int i=0;i<pMainWindow->editorList()->pageCount();i++) {
Editor* e= (*(pMainWindow->editorList()))[i];
if (e && e->inProject())
sl.append(QString("%1").arg(indexInUnits(e)));
}
layIni.beginGroup("Editors");
layIni.setValue("Order",sl.join(","));
Editor *e, *e2;
// Remember what files were visible
pMainWindow->editorList()->getVisibleEditors(e, e2);
if (e)
layIni.setValue("Focused", indexInUnits(e));
layIni.endGroup();
// save editor info
for (int i=0;i<mUnits.count();i++) {
layIni.beginGroup(QString("Editor_%1").arg(i));
PProjectUnit unit = mUnits[i];
Editor* editor = unit->editor();
if (editor) {
layIni.setValue("CursorCol", editor->caretX());
layIni.setValue("CursorRow", editor->caretY());
layIni.setValue("TopLine", editor->topLine());
layIni.setValue("LeftChar", editor->leftChar());
}
layIni.endGroup();
// remove old data from project file
mIniFile->beginGroup(QString("Unit%1").arg(i+1));
mIniFile->remove("Open");
mIniFile->remove("Top");
mIniFile->remove("CursorCol");
mIniFile->remove("CursorRow");
mIniFile->remove("TopLine");
mIniFile->remove("LeftChar");
mIniFile->endGroup();
}
}
2021-09-10 23:41:38 +08:00
void Project::saveUnitAs(int i, const QString &sFileName)
{
if ((i < 0) || (i >= mUnits.count()))
return;
PProjectUnit unit = mUnits[i];
// if (fileExists(unit->fileName())) {
// unit->setNew(false);
// }
unit->setNew(false);
unit->setFileName(sFileName);
mIniFile->beginGroup(QString("Unit%1").arg(i+1));
mIniFile->setValue("FileName",
extractRelativePath(
directory(),
sFileName));
mIniFile->endGroup();
mIniFile->sync();
setModified(true);
}
void Project::saveUnitLayout(Editor *e, int index)
{
if (!e)
return;
QSettings layIni = QSettings(changeFileExt(filename(), "layout"));
layIni.beginGroup(QString("Editor_%1").arg(index));
layIni.setValue("CursorCol", e->caretX());
layIni.setValue("CursorRow", e->caretY());
layIni.setValue("TopLine", e->topLine());
layIni.setValue("LeftChar", e->leftChar());
layIni.endGroup();
}
bool Project::saveUnits()
{
int count = 0;
for (int idx = 0; idx < mUnits.count(); idx++) {
PProjectUnit unit = mUnits[idx];
bool rd_only = false;
2021-09-11 11:42:20 +08:00
mIniFile->beginGroup(QString("Unit%1").arg(count+1));
2021-09-10 23:41:38 +08:00
if (unit->modified() && fileExists(unit->fileName())
2021-09-11 11:42:20 +08:00
&& isReadOnly(unit->fileName())) {
2021-09-10 23:41:38 +08:00
// file is read-only
QMessageBox::critical(pMainWindow,
tr("Can't save file"),
tr("Can't save file '%1'").arg(unit->fileName()),
QMessageBox::Ok
);
rd_only = true;
}
if (!rd_only) {
if (!unit->save() && unit->isNew())
return false;
}
// saved new file or an existing file add to project file
mIniFile->setValue("FileName",
extractRelativePath(
directory(),
unit->fileName()));
count++;
switch(getFileType(unit->fileName())) {
case FileType::CHeader:
case FileType::CSource:
case FileType::CppHeader:
case FileType::CppSource:
mIniFile->setValue("CompileCpp", unit->compileCpp());
break;
case FileType::WindowsResourceSource:
unit->setFolder("Resources");
}
mIniFile->setValue("Folder", unit->folder());
mIniFile->setValue("Compile", unit->compile());
mIniFile->setValue("Link", unit->link());
mIniFile->setValue("Priority", unit->priority());
mIniFile->setValue("OverrideBuildCmd", unit->overrideBuildCmd());
mIniFile->setValue("BuildCmd", unit->buildCmd());
mIniFile->setValue("DetectEncoding", unit->encoding()==ENCODING_AUTO_DETECT);
mIniFile->setValue("FileEncoding", unit->encoding());
mIniFile->endGroup();
}
mIniFile->beginGroup("Project");
mIniFile->setValue("UnitCount",count);
mIniFile->endGroup();
mIniFile->sync();
return true;
}
void Project::setCompilerOption(const QString &optionString, const QChar &value)
{
if (mOptions.compilerSet<0 || mOptions.compilerSet>=pSettings->compilerSets().size()) {
return;
}
std::shared_ptr<Settings::CompilerSet> compilerSet = pSettings->compilerSets().list()[mOptions.compilerSet];
int optionIndex = compilerSet->findOptionIndex(optionString);
// Does the option exist?
if (optionIndex>=0){
mOptions.compilerOptions[optionIndex] = value;
}
}
2021-09-11 09:21:44 +08:00
void Project::updateFolders()
{
mFolders.clear();
updateFolderNode(mNode);
for (int idx = 0; idx < mUnits.count();idx++)
mUnits[idx]->setFolder(
getFolderPath(
mUnits[idx]->node()->parent.lock()
)
);
setModified(true);
}
void Project::updateNodeIndexes()
{
for (int idx = 0;idx<mUnits.count();idx++)
mUnits[idx]->node()->unitIndex = idx;
}
2021-09-10 21:37:52 +08:00
void Project::saveOptions()
{
2021-09-10 23:41:38 +08:00
mIniFile->beginGroup("Project");
mIniFile->setValue("FileName", extractRelativePath(directory(), mFilename));
mIniFile->setValue("Name", mName);
mIniFile->setValue("Type", static_cast<int>(mOptions.type));
mIniFile->setValue("Ver", 3); // Is 3 as of Red Panda Dev-C++ 7.0
mIniFile->setValue("ObjFiles", mOptions.objFiles.join(";"));
mIniFile->setValue("Includes", mOptions.includes.join(";"));
mIniFile->setValue("Libs", mOptions.libs.join(";"));
mIniFile->setValue("PrivateResource", mOptions.privateResource);
mIniFile->setValue("ResourceIncludes", mOptions.resourceIncludes.join(";"));
mIniFile->setValue("MakeIncludes", mOptions.makeIncludes.join(";"));
mIniFile->setValue("Compiler", mOptions.compilerCmd);
mIniFile->setValue("CppCompiler", mOptions.cppCompilerCmd);
mIniFile->setValue("Linker", mOptions.linkerCmd);
mIniFile->setValue("IsCpp", mOptions.useGPP);
mIniFile->setValue("Icon", extractRelativePath(directory(), mOptions.icon));
mIniFile->setValue("ExeOutput", mOptions.exeOutput);
mIniFile->setValue("ObjectOutput", mOptions.objectOutput);
mIniFile->setValue("LogOutput", mOptions.logOutput);
mIniFile->setValue("LogOutputEnabled", mOptions.logOutputEnabled);
mIniFile->setValue("OverrideOutput", mOptions.overrideOutput);
mIniFile->setValue("OverrideOutputName", mOptions.overridenOutput);
mIniFile->setValue("HostApplication", mOptions.hostApplication);
mIniFile->setValue("UseCustomMakefile", mOptions.useCustomMakefile);
mIniFile->setValue("CustomMakefile", mOptions.customMakefile);
mIniFile->setValue("UsePrecompiledHeader", mOptions.usePrecompiledHeader);
mIniFile->setValue("PrecompiledHeader", mOptions.precompiledHeader);
mIniFile->setValue("CommandLine", mOptions.cmdLineArgs);
mIniFile->setValue("Folders", mFolders.join(";"));
mIniFile->setValue("IncludeVersionInfo", mOptions.includeVersionInfo);
mIniFile->setValue("SupportXPThemes", mOptions.supportXPThemes);
mIniFile->setValue("CompilerSet", mOptions.compilerSet);
mIniFile->setValue("CompilerSettings", mOptions.compilerOptions);
mIniFile->setValue("StaticLink", mOptions.staticLink);
mIniFile->setValue("AddCharset", mOptions.addCharset);
mIniFile->setValue("Encoding",mOptions.encoding);
//for Red Panda Dev C++ 6 compatibility
mIniFile->setValue("UseUTF8",mOptions.encoding == ENCODING_UTF8);
mIniFile->endGroup();
mIniFile->beginGroup("VersionInfo");
mIniFile->setValue("Major", mOptions.versionInfo.major);
mIniFile->setValue("Minor", mOptions.versionInfo.minor);
mIniFile->setValue("Release", mOptions.versionInfo.release);
mIniFile->setValue("Build", mOptions.versionInfo.build);
mIniFile->setValue("LanguageID", mOptions.versionInfo.languageID);
mIniFile->setValue("CharsetID", mOptions.versionInfo.charsetID);
mIniFile->setValue("CompanyName", mOptions.versionInfo.companyName);
mIniFile->setValue("FileVersion", mOptions.versionInfo.fileVersion);
mIniFile->setValue("FileDescription", mOptions.versionInfo.fileDescription);
mIniFile->setValue("InternalName", mOptions.versionInfo.internalName);
mIniFile->setValue("LegalCopyright", mOptions.versionInfo.legalCopyright);
mIniFile->setValue("LegalTrademarks", mOptions.versionInfo.legalTrademarks);
mIniFile->setValue("OriginalFilename", mOptions.versionInfo.originalFilename);
mIniFile->setValue("ProductName", mOptions.versionInfo.productName);
mIniFile->setValue("ProductVersion", mOptions.versionInfo.productVersion);
mIniFile->setValue("AutoIncBuildNr", mOptions.versionInfo.autoIncBuildNr);
mIniFile->setValue("SyncProduct", mOptions.versionInfo.syncProduct);
mIniFile->endGroup();
//delete outdated dev4 project options
mIniFile->beginGroup("Project");
mIniFile->remove("NoConsole");
mIniFile->remove("IsDLL");
mIniFile->remove("ResFiles");
mIniFile->remove("IncludeDirs");
mIniFile->remove("CompilerOptions");
mIniFile->remove("Use_GPP");
mIniFile->endGroup();
mIniFile->sync(); // force flush
2021-09-10 21:37:52 +08:00
}
2021-09-07 10:28:40 +08:00
void Project::addFolder(const QString &s)
{
if (mFolders.indexOf(s)<0) {
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-07 10:28:40 +08:00
mFolders.append(s);
rebuildNodes();
//todo: MainForm.ProjectView.Select(FolderNodeFromName(s));
//folderNodeFromName(s)->makeVisible();
setModified(true);
}
}
PProjectUnit Project::addUnit(const QString &inFileName, PFolderNode parentNode, bool rebuild)
{
PProjectUnit newUnit;
// Don't add if it already exists
if (fileAlreadyExists(inFileName)) {
QMessageBox::critical(pMainWindow,
tr("File Exists"),
tr("File '%1' is already in the project"),
QMessageBox::Ok);
return newUnit;
}
newUnit = std::make_shared<ProjectUnit>(this);
// Set all properties
newUnit->setFileName(QDir(directory()).filePath(inFileName));
newUnit->setNew(false);
newUnit->setEditor(nullptr);
newUnit->setFolder(getFolderPath(parentNode));
2021-09-10 12:37:02 +08:00
newUnit->setNode(makeNewFileNode(extractFileName(newUnit->fileName()), false, parentNode));
2021-09-07 10:28:40 +08:00
newUnit->node()->unitIndex = mUnits.count();
mUnits.append(newUnit);
// Determine compilation flags
switch(getFileType(inFileName)) {
case FileType::CSource:
newUnit->setCompile(true);
newUnit->setCompileCpp(mOptions.useGPP);
newUnit->setLink(true);
break;
case FileType::CppSource:
newUnit->setCompile(true);
newUnit->setCompileCpp(true);
newUnit->setLink(true);
break;
case FileType::WindowsResourceSource:
newUnit->setCompile(true);
newUnit->setCompileCpp(mOptions.useGPP);
newUnit->setLink(false);
break;
default:
newUnit->setCompile(false);
newUnit->setCompileCpp(false);
newUnit->setLink(false);
}
newUnit->setPriority(1000);
newUnit->setOverrideBuildCmd(false);
newUnit->setBuildCmd("");
2021-09-11 09:21:44 +08:00
if (rebuild) {
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-07 10:28:40 +08:00
rebuildNodes();
2021-09-11 09:21:44 +08:00
}
2021-09-07 10:28:40 +08:00
setModified(true);
return newUnit;
}
void Project::buildPrivateResource(bool forceSave)
{
int comp = 0;
foreach (const PProjectUnit& unit,mUnits) {
if (
(getFileType(unit->fileName()) == FileType::WindowsResourceSource)
&& unit->compile() )
comp++;
}
// if project has no other resources included
// and does not have an icon
// and does not include the XP style manifest
// and does not include version info
// then do not create a private resource file
if ((comp == 0) &&
(! mOptions.supportXPThemes)
&& (! mOptions.includeVersionInfo)
&& (mOptions.icon == "")) {
mOptions.privateResource="";
return;
}
// change private resource from <project_filename>.res
// to <project_filename>_private.res
//
// in many cases (like in importing a MSVC project)
// the project's resource file has already the
// <project_filename>.res filename.
2021-09-07 14:04:48 +08:00
QString rcFile;
2021-09-07 10:28:40 +08:00
if (!mOptions.privateResource.isEmpty()) {
2021-09-07 14:04:48 +08:00
rcFile = QDir(directory()).filePath(mOptions.privateResource);
if (changeFileExt(rcFile, DEV_PROJECT_EXT) == mFilename)
rcFile = changeFileExt(mFilename,QString("_private") + RC_EXT);
2021-09-07 10:28:40 +08:00
} else
2021-09-07 14:04:48 +08:00
rcFile = changeFileExt(mFilename,QString("_private") + RC_EXT);
rcFile = extractRelativePath(mFilename, rcFile);
rcFile.replace(' ','_');
2021-09-07 10:28:40 +08:00
// don't run the private resource file and header if not modified,
// unless ForceSave is true
if (!forceSave
2021-09-07 14:04:48 +08:00
&& fileExists(rcFile)
&& fileExists(changeFileExt(rcFile, H_EXT))
2021-09-07 10:28:40 +08:00
&& !mModified)
return;
2021-09-07 16:49:35 +08:00
QStringList contents;
contents.append("/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */");
contents.append("/* DO NOT EDIT! */");
contents.append("");
2021-09-07 10:28:40 +08:00
if (mOptions.includeVersionInfo) {
2021-09-07 16:49:35 +08:00
contents.append("#include <windows.h> // include for version info constants");
contents.append("");
2021-09-07 14:04:48 +08:00
}
2021-09-07 10:28:40 +08:00
foreach (const PProjectUnit& unit, mUnits) {
if (
(getFileType(unit->fileName()) == FileType::WindowsResourceSource)
&& unit->compile() )
2021-09-07 16:49:35 +08:00
contents.append("#include \"" +
2021-09-07 10:28:40 +08:00
genMakePath(
extractRelativePath(directory(), unit->fileName()),
false,
false) + "\"");
}
if (!mOptions.icon.isEmpty()) {
2021-09-07 16:49:35 +08:00
contents.append("");
2021-09-07 10:28:40 +08:00
QString icon = QDir(directory()).absoluteFilePath(mOptions.icon);
if (fileExists(icon)) {
icon = extractRelativePath(mFilename, icon);
icon.replace('\\', '/');
2021-09-07 16:49:35 +08:00
contents.append("A ICON \"" + icon + '"');
2021-09-07 10:28:40 +08:00
} else
mOptions.icon = "";
}
if (mOptions.supportXPThemes) {
2021-09-07 16:49:35 +08:00
contents.append("");
contents.append("//");
contents.append("// SUPPORT FOR WINDOWS XP THEMES:");
contents.append("// THIS WILL MAKE THE PROGRAM USE THE COMMON CONTROLS");
contents.append("// LIBRARY VERSION 6.0 (IF IT IS AVAILABLE)");
contents.append("//");
2021-09-07 10:28:40 +08:00
if (!mOptions.exeOutput.isEmpty())
2021-09-07 16:49:35 +08:00
contents.append(
2021-09-07 10:28:40 +08:00
"1 24 \"" +
genMakePath2(
includeTrailingPathDelimiter(mOptions.exeOutput)
2021-09-10 12:37:02 +08:00
+ extractFileName(executable()))
2021-09-07 10:28:40 +08:00
+ ".Manifest\"");
else
2021-09-10 12:37:02 +08:00
contents.append("1 24 \"" + extractFileName(executable()) + ".Manifest\"");
2021-09-07 14:04:48 +08:00
}
if (mOptions.includeVersionInfo) {
2021-09-07 16:49:35 +08:00
contents.append("");
contents.append("//");
contents.append("// TO CHANGE VERSION INFORMATION, EDIT PROJECT OPTIONS...");
contents.append("//");
contents.append("1 VERSIONINFO");
contents.append("FILEVERSION " +
2021-09-07 14:04:48 +08:00
QString("%1,%2,%3,%4")
.arg(mOptions.versionInfo.major)
.arg(mOptions.versionInfo.minor)
.arg(mOptions.versionInfo.release)
.arg(mOptions.versionInfo.build));
2021-09-07 16:49:35 +08:00
contents.append("PRODUCTVERSION " +
2021-09-07 14:04:48 +08:00
QString("%1,%2,%3,%4")
.arg(mOptions.versionInfo.major)
.arg(mOptions.versionInfo.minor)
.arg(mOptions.versionInfo.release)
.arg(mOptions.versionInfo.build));
switch(mOptions.type) {
case ProjectType::GUI:
case ProjectType::Console:
2021-09-07 16:49:35 +08:00
contents.append("FILETYPE VFT_APP");
2021-09-07 14:04:48 +08:00
break;
case ProjectType::StaticLib:
2021-09-07 16:49:35 +08:00
contents.append("FILETYPE VFT_STATIC_LIB");
2021-09-07 14:04:48 +08:00
break;
case ProjectType::DynamicLib:
2021-09-07 16:49:35 +08:00
contents.append("FILETYPE VFT_DLL");
2021-09-07 14:04:48 +08:00
break;
}
2021-09-07 16:49:35 +08:00
contents.append("{");
contents.append(" BLOCK \"StringFileInfo\"");
contents.append(" {");
contents.append(" BLOCK \"" +
2021-09-07 14:04:48 +08:00
QString("%1%2")
.arg(mOptions.versionInfo.languageID,4,16,QChar('0'))
.arg(mOptions.versionInfo.charsetID,4,16,QChar('0'))
+ '"');
2021-09-07 16:49:35 +08:00
contents.append(" {");
contents.append(" VALUE \"CompanyName\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.companyName
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"FileVersion\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.fileVersion
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"FileDescription\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.fileDescription
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"InternalName\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.internalName
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"LegalCopyright\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.legalCopyright
+ '"');
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"LegalTrademarks\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.legalTrademarks
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"OriginalFilename\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.originalFilename
+ "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"ProductName\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.productName + "\"");
2021-09-07 16:49:35 +08:00
contents.append(" VALUE \"ProductVersion\", \""
2021-09-07 14:04:48 +08:00
+ mOptions.versionInfo.productVersion + "\"");
2021-09-07 16:49:35 +08:00
contents.append(" }");
contents.append(" }");
2021-09-07 14:04:48 +08:00
// additional block for windows 95->NT
2021-09-07 16:49:35 +08:00
contents.append(" BLOCK \"VarFileInfo\"");
contents.append(" {");
contents.append(" VALUE \"Translation\", " +
2021-09-07 14:04:48 +08:00
QString("0x%1, %2")
.arg(mOptions.versionInfo.languageID,4,16,QChar('0'))
.arg(mOptions.versionInfo.charsetID));
2021-09-07 16:49:35 +08:00
contents.append(" }");
2021-09-07 14:04:48 +08:00
2021-09-07 16:49:35 +08:00
contents.append("}");
2021-09-07 10:28:40 +08:00
}
2021-09-07 14:04:48 +08:00
rcFile = QDir(directory()).absoluteFilePath(rcFile);
2021-09-07 16:49:35 +08:00
if (contents.count() > 3) {
StringsToFile(contents,rcFile);
2021-09-07 14:04:48 +08:00
mOptions.privateResource = extractRelativePath(directory(), rcFile);
} else {
if (fileExists(rcFile))
QFile::remove(rcFile);
QString resFile = changeFileExt(rcFile, RES_EXT);
if (fileExists(resFile))
QFile::remove(resFile);
mOptions.privateResource = "";
}
// if fileExists(Res) then
// FileSetDate(Res, DateTimeToFileDate(Now)); // fix the "Clock skew detected" warning ;)
2021-09-07 10:28:40 +08:00
// create XP manifest
2021-09-07 14:04:48 +08:00
if (mOptions.supportXPThemes) {
QStringList content;
content.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
content.append("<assembly");
content.append(" xmlns=\"urn:schemas-microsoft-com:asm.v1\"");
content.append(" manifestVersion=\"1.0\">");
content.append("<assemblyIdentity");
QString name = mName;
name.replace(' ','_');
content.append(" name=\"DevCpp.Apps." + name + '\"');
content.append(" processorArchitecture=\"*\"");
content.append(" version=\"1.0.0.0\"");
content.append(" type=\"win32\"/>");
content.append("<description>" + name + "</description>");
content.append("<dependency>");
content.append(" <dependentAssembly>");
content.append(" <assemblyIdentity");
content.append(" type=\"win32\"");
content.append(" name=\"Microsoft.Windows.Common-Controls\"");
content.append(" version=\"6.0.0.0\"");
content.append(" processorArchitecture=\"*\"");
content.append(" publicKeyToken=\"6595b64144ccf1df\"");
content.append(" language=\"*\"");
content.append(" />");
content.append(" </dependentAssembly>");
content.append("</dependency>");
content.append("</assembly>");
StringsToFile(content,executable() + ".Manifest");
} else if (fileExists(executable() + ".Manifest"))
QFile::remove(executable() + ".Manifest");
2021-09-07 10:28:40 +08:00
// create private header file
2021-09-07 14:04:48 +08:00
QString hFile = changeFileExt(rcFile, H_EXT);
2021-09-07 16:49:35 +08:00
contents.clear();
2021-09-10 12:37:02 +08:00
QString def = extractFileName(rcFile);
2021-09-07 14:04:48 +08:00
def.replace(".","_");
2021-09-07 16:49:35 +08:00
contents.append("/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */");
contents.append("/* DO NOT EDIT ! */");
contents.append("");
contents.append("#ifndef " + def);
contents.append("#define " + def);
contents.append("");
contents.append("/* VERSION DEFINITIONS */");
contents.append("#define VER_STRING\t" +
2021-09-07 14:04:48 +08:00
QString("\"%d.%d.%d.%d\"")
.arg(mOptions.versionInfo.major)
.arg(mOptions.versionInfo.minor)
.arg(mOptions.versionInfo.release)
.arg(mOptions.versionInfo.build));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define VER_MAJOR\t%1").arg(mOptions.versionInfo.major));
contents.append(QString("#define VER_MINOR\t%1").arg(mOptions.versionInfo.minor));
contents.append(QString("#define VER_RELEASE\t").arg(mOptions.versionInfo.release));
contents.append(QString("#define VER_BUILD\t").arg(mOptions.versionInfo.build));
contents.append(QString("#define COMPANY_NAME\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.companyName));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define FILE_VERSION\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.fileVersion));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define FILE_DESCRIPTION\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.fileDescription));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define INTERNAL_NAME\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.internalName));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define LEGAL_COPYRIGHT\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.legalCopyright));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define LEGAL_TRADEMARKS\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.legalTrademarks));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define ORIGINAL_FILENAME\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.originalFilename));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define PRODUCT_NAME\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.productName));
2021-09-07 16:49:35 +08:00
contents.append(QString("#define PRODUCT_VERSION\t\"%1\"")
2021-09-07 14:04:48 +08:00
.arg(mOptions.versionInfo.productVersion));
2021-09-07 16:49:35 +08:00
contents.append("");
contents.append("#endif /*" + def + "*/");
StringsToFile(contents,hFile);
}
void Project::checkProjectFileForUpdate()
{
bool cnvt = false;
mIniFile->beginGroup("Project");
int uCount = mIniFile->value("UnitCount", 0).toInt();
mIniFile->endGroup();
// check if using old way to store resources and fix it
QString oldRes = mIniFile->value("Resources", "").toString();
if (!oldRes.isEmpty()) {
QFile::copy(mFilename,mFilename+".bak");
QStringList sl;
sl = oldRes.split(';');
for (int i=0;i<sl.count();i++){
const QString& s = sl[i];
mIniFile->beginGroup(QString("Unit%1").arg(uCount+i));
mIniFile->setValue("Filename", s);
mIniFile->setValue("Folder", "Resources");
mIniFile->setValue("Compile",true);
mIniFile->endGroup();
}
mIniFile->beginGroup("Project");
mIniFile->setValue("UnitCount",uCount+sl.count());
QString folders = mIniFile->value("Folders","").toString();
if (!folders.isEmpty())
folders += ",Resources";
else
folders = "Resources";
mIniFile->setValue("Folders",folders);
mIniFile->endGroup();
}
mIniFile->beginGroup("Project");
mIniFile->remove("Resources");
mIniFile->remove("Focused");
mIniFile->remove("Order");
mIniFile->remove("DebugInfo");
mIniFile->remove("ProfileInfo");
if (cnvt)
QMessageBox::information(
pMainWindow,
tr("Project Updated"),
tr("Your project was succesfully updated to a newer file format!")
+"<br />"
+tr("If something has gone wrong, we kept a backup-file: '%1'...")
.arg(mFilename+".bak"),
QMessageBox::Ok);
}
void Project::closeUnit(int index)
{
PProjectUnit unit = mUnits[index];
if (unit->editor()) {
saveUnitLayout(unit->editor(),index);
pMainWindow->editorList()->forceCloseEditor(unit->editor());
unit->setEditor(nullptr);
}
}
void Project::createFolderNodes()
{
mFolderNodes.clear();
for (int idx=0;idx<mFolders.count();idx++) {
PFolderNode node = mNode;
QString s = mFolders[idx];
int i = s.indexOf('/');
while (i>=0) {
PFolderNode findnode;
for (int c=0;c<node->children.count();c++) {
if (node->children[c]->text == s.mid(0,i))
findnode = node->children[c];
}
if (!findnode)
node = makeNewFileNode(s.mid(0,i),true,node);
else
node = findnode;
node->unitIndex = -1;
s.remove(0,i);
i = s.indexOf('/');
}
node = makeNewFileNode(s, true, node);
node->unitIndex = -1;
mFolderNodes.append(node);
}
}
void Project::doAutoOpen()
{
//todo:
// case devData.AutoOpen of
// 0: begin
// for i := 0 to pred(fUnits.Count) do
// OpenUnit(i); // Open all
// if fUnits.Count > 0 then
// fUnits[0].Editor.Activate; // Show first
// end;
// 1:
// if fUnits.Count > 0 then
// OpenUnit(0).Activate; // Open and show first
// 2:
// LoadLayout; // Open previous selection
// end;
}
2021-09-09 00:15:12 +08:00
bool Project::fileAlreadyExists(const QString &s)
{
foreach (const PProjectUnit& unit, mUnits) {
if (unit->fileName() == s)
return true;
}
return false;
}
PFolderNode Project::folderNodeFromName(const QString &name)
{
int index = mFolders.indexOf(name);
if (index>=0) {
return mFolderNodes[index];
}
return mNode;
}
2021-09-09 11:47:04 +08:00
QChar Project::getCompilerOption(const QString &optionString)
{
// Does the option exist?
Settings::PCompilerSet compilerSet = pSettings->compilerSets().getSet(mOptions.compilerSet);
if (!compilerSet)
return '0';
int index = compilerSet->findOptionIndex(optionString);
if (index>=0 && index<mOptions.compilerOptions.length()) {
return mOptions.compilerOptions[index];
}
return '0';
}
QString Project::getFolderPath(PFolderNode node)
{
QString result;
if (!node)
return result;
if (node->unitIndex>=0) // not a folder
return result;
2021-09-10 10:27:01 +08:00
PFolderNode p = node;
2021-09-09 11:47:04 +08:00
while (p && p->unitIndex==-1) {
if (!result.isEmpty())
result = p->text + "/" + result;
2021-09-10 10:27:01 +08:00
p = p->parent.lock();
2021-09-09 11:47:04 +08:00
}
return result;
}
int Project::getUnitFromString(const QString &s)
{
return indexInUnits(s);
}
2021-09-09 18:36:54 +08:00
void Project::incrementBuildNumber()
{
mOptions.versionInfo.build++;
mOptions.versionInfo.fileVersion = QString("%1.%2.%3.%3")
.arg(mOptions.versionInfo.major)
.arg(mOptions.versionInfo.minor)
.arg(mOptions.versionInfo.release)
.arg(mOptions.versionInfo.build);
if (mOptions.versionInfo.syncProduct)
mOptions.versionInfo.productVersion = mOptions.versionInfo.fileVersion;
setModified(true);
}
QString Project::listUnitStr(const QChar &separator)
{
QStringList units;
foreach (const PProjectUnit& unit, mUnits) {
units.append('"'+unit->fileName()+'"');
}
return units.join(separator);
}
void Project::loadLayout()
{
QSettings layIni = QSettings(changeFileExt(filename(), "layout"),QSettings::IniFormat);
layIni.beginGroup("Editors");
int topLeft = layIni.value("Focused", -1).toInt();
//TopRight := layIni.ReadInteger('Editors', 'FocusedRight', -1);
QString temp =layIni.value("Order", "").toString();
layIni.endGroup();
QStringList sl = temp.split(",");
foreach (const QString& s,sl) {
bool ok;
int currIdx = s.toInt(&ok);
if (ok) {
openUnit(currIdx);
}
}
if (topLeft>=0 && topLeft<mUnits.count() && mUnits[topLeft]->editor()) {
mUnits[topLeft]->editor()->activate();
}
}
2021-09-09 23:20:00 +08:00
void Project::loadOptions()
{
mIniFile->beginGroup("Project");
mName = mIniFile->value("name", "").toString();
mOptions.icon = mIniFile->value("icon", "").toString();
mOptions.version = mIniFile->value("Ver", 0).toInt();
if (mOptions.version > 0) { // ver > 0 is at least a v5 project
if (mOptions.version < 2) {
mOptions.version = 2;
QMessageBox::information(pMainWindow,
tr("Settings need update"),
tr("The compiler settings format of Dev-C++ has changed.")
+"<BR /><BR />"
+tr("Please update your settings at Project >> Project Options >> Compiler and save your project."),
QMessageBox::Ok);
}
mOptions.type = static_cast<ProjectType>(mIniFile->value("type", 0).toInt());
mOptions.compilerCmd = mIniFile->value("Compiler", "").toString();
mOptions.cppCompilerCmd = mIniFile->value("CppCompiler", "").toString();
2021-09-10 10:27:01 +08:00
mOptions.linkerCmd = mIniFile->value("Linker", "").toString();
mOptions.objFiles = mIniFile->value("ObjFiles", "").toString().split(";");
mOptions.libs = mIniFile->value("Libs", "").toString().split(";");
mOptions.includes = mIniFile->value("Includes", "").toString().split(";");
mOptions.privateResource = mIniFile->value("PrivateResource", "").toString();
mOptions.resourceIncludes = mIniFile->value("ResourceIncludes", "").toString().split(";");
mOptions.makeIncludes = mIniFile->value("MakeIncludes","").toString().split(";");
mOptions.useGPP = mIniFile->value("IsCpp", false).toBool();
mOptions.exeOutput = mIniFile->value("ExeOutput", "").toString();
mOptions.objectOutput = mIniFile->value("ObjectOutput", "").toString();
mOptions.logOutput = mIniFile->value("LogOutput","").toString();
mOptions.logOutputEnabled = mIniFile->value("LogOutputEnabled", false).toBool();
mOptions.overrideOutput = mIniFile->value("OverrideOutput", false).toBool();
mOptions.overridenOutput = mIniFile->value("OverrideOutputName","").toString();
mOptions.hostApplication = mIniFile->value("HostApplication","").toString();
mOptions.useCustomMakefile = mIniFile->value("UseCustomMakefile", false).toBool();
mOptions.customMakefile = mIniFile->value("CustomMakefile","").toString();
mOptions.usePrecompiledHeader = mIniFile->value("UsePrecompiledHeader", false).toBool();
mOptions.precompiledHeader = mIniFile->value("PrecompiledHeader","").toString();
mOptions.cmdLineArgs = mIniFile->value("CommandLine","").toString();
mFolders = mIniFile->value("Folders","").toString().split(";");
mOptions.includeVersionInfo = mIniFile->value("IncludeVersionInfo", false).toBool();
mOptions.supportXPThemes = mIniFile->value("SupportXPThemes", false).toBool();
mOptions.compilerSet = mIniFile->value("CompilerSet", pSettings->compilerSets().defaultIndex()).toInt();
if (mOptions.compilerSet >= pSettings->compilerSets().size()
|| mOptions.compilerSet < 0) { // TODO: change from indices to names
QMessageBox::critical(
pMainWindow,
tr("Compiler not found"),
tr("The compiler set you have selected for this project, no longer exists.")
+"<BR />"
+tr("It will be substituted by the global compiler set."),
QMessageBox::Ok
);
mOptions.compilerSet = pSettings->compilerSets().defaultIndex();
setModified(true);
}
mOptions.compilerOptions = mIniFile->value("CompilerSettings","").toString();
mOptions.staticLink = mIniFile->value("StaticLink", true).toBool();
mOptions.addCharset = mIniFile->value("AddCharset", true).toBool();
2021-09-10 23:41:38 +08:00
bool useUTF8 = mIniFile->value("UseUTF8", false).toBool();
if (useUTF8) {
mOptions.encoding = mIniFile->value("Encoding", ENCODING_SYSTEM_DEFAULT).toString();
} else {
mOptions.encoding = mIniFile->value("Encoding", ENCODING_UTF8).toString();
}
2021-09-10 10:27:01 +08:00
mOptions.versionInfo.major = mIniFile->value("Major", 0).toInt();
mOptions.versionInfo.minor = mIniFile->value("Minor", 1).toInt();
mOptions.versionInfo.release = mIniFile->value("Release", 1).toInt();
mOptions.versionInfo.build = mIniFile->value("Build", 1).toInt();
mOptions.versionInfo.languageID = mIniFile->value("LanguageID", 0x0409).toInt();
mOptions.versionInfo.charsetID = mIniFile->value("CharsetID", 0x04E4).toInt();
mOptions.versionInfo.companyName = mIniFile->value("CompanyName","").toString();
mOptions.versionInfo.fileVersion = mIniFile->value("FileVersion", "0.1").toString();
mOptions.versionInfo.fileDescription = mIniFile->value("FileDescription",
tr("Developed using the Red Panda Dev-C++ IDE")).toString();
mOptions.versionInfo.internalName = mIniFile->value("InternalName","").toString();
mOptions.versionInfo.legalCopyright = mIniFile->value("LegalCopyright","").toString();
mOptions.versionInfo.legalTrademarks = mIniFile->value("LegalTrademarks","").toString();
mOptions.versionInfo.originalFilename = mIniFile->value("OriginalFilename",
2021-09-10 12:37:02 +08:00
extractFileName(executable())).toString();
2021-09-10 10:27:01 +08:00
mOptions.versionInfo.productName = mIniFile->value("ProductName", mName).toString();
mOptions.versionInfo.productVersion = mIniFile->value("ProductVersion", "0.1.1.1").toString();
mOptions.versionInfo.autoIncBuildNr = mIniFile->value("AutoIncBuildNr", false).toBool();
mOptions.versionInfo.syncProduct = mIniFile->value("SyncProduct", false).toBool();
} else { // dev-c < 4
mOptions.version = -1;
if (!mIniFile->value("NoConsole", true).toBool())
mOptions.type = ProjectType::Console;
else if (mIniFile->value("IsDLL", false).toBool())
mOptions.type = ProjectType::DynamicLib;
2021-09-09 23:20:00 +08:00
else
2021-09-10 10:27:01 +08:00
mOptions.type = ProjectType::GUI;
mOptions.privateResource = mIniFile->value("PrivateResource","").toString();
mOptions.resourceIncludes = mIniFile->value("ResourceIncludes","").toString().split(";");
mOptions.objFiles = mIniFile->value("ObjFiles","").toString().split(";");
mOptions.includes = mIniFile->value("IncludeDirs","").toString().split(";");
mOptions.compilerCmd = mIniFile->value("CompilerOptions","").toString();
mOptions.useGPP = mIniFile->value("Use_GPP", false).toBool();
mOptions.exeOutput = mIniFile->value("ExeOutput","").toString();
mOptions.objectOutput = mIniFile->value("ObjectOutput","").toString();
mOptions.overrideOutput = mIniFile->value("OverrideOutput", false).toBool();
mOptions.overridenOutput = mIniFile->value("OverrideOutputName","").toString();
mOptions.hostApplication = mIniFile->value("HostApplication","").toString();
}
2021-09-09 23:20:00 +08:00
}
2021-09-10 15:03:47 +08:00
void Project::loadUnitLayout(Editor *e, int index)
{
if (!e)
return;
2021-09-10 21:37:52 +08:00
QSettings layIni(changeFileExt(filename(), "layout"), QSettings::IniFormat);
2021-09-10 15:03:47 +08:00
layIni.beginGroup(QString("Editor_%1").arg(index));
e->setCaretY(layIni.value("CursorRow",1).toInt());
e->setCaretX(layIni.value("CursorCol",1).toInt());
e->setTopLine(layIni.value("TopLine",1).toInt());
e->setLeftChar(layIni.value("LeftChar",1).toInt());
layIni.endGroup();
}
2021-09-07 16:49:35 +08:00
PCppParser Project::cppParser()
{
return mParser;
2021-09-07 00:32:16 +08:00
}
2021-09-06 12:58:29 +08:00
2021-09-07 00:32:16 +08:00
void Project::sortUnitsByPriority()
{
2021-09-11 09:21:44 +08:00
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
2021-09-07 00:32:16 +08:00
std::sort(mUnits.begin(),mUnits.end(),[](const PProjectUnit& u1, const PProjectUnit& u2)->bool{
return (u1->priority()>u2->priority());
});
2021-09-11 09:21:44 +08:00
rebuildNodes();
}
void Project::sortUnitsByAlpha()
{
mModel.beginUpdate();
auto action = finally([this]{
mModel.endUpdate();
});
std::sort(mUnits.begin(),mUnits.end(),[](const PProjectUnit& u1, const PProjectUnit& u2)->bool{
return (extractFileName(u1->fileName())<extractFileName(u2->fileName()));
});
rebuildNodes();
2021-09-07 00:32:16 +08:00
}
2021-09-06 12:58:29 +08:00
2021-09-09 11:47:04 +08:00
int Project::indexInUnits(const QString &fileName) const
{
QDir dir(directory());
for (int i=0;i<mUnits.count();i++) {
PProjectUnit unit = mUnits[i];
if (dir.absoluteFilePath(fileName) == dir.absoluteFilePath(unit->fileName()))
return i;
}
return -1;
}
int Project::indexInUnits(const Editor *editor) const
{
if (!editor)
return -1;
return indexInUnits(editor->filename());
}
2021-09-10 21:37:52 +08:00
void Project::removeFolderRecurse(PFolderNode node)
{
if (!node)
return ;
// Recursively remove folders
for (int i=node->children.count()-1;i>=0;i++) {
PFolderNode childNode = node->children[i];
// Remove folder inside folder
if (childNode->unitIndex<0 && childNode->level>0) {
removeFolderRecurse(childNode);
// Or remove editors at this level
} else if (childNode->unitIndex >= 0 && childNode->level > 0) {
// Remove editor in folder from project
int editorIndex = childNode->unitIndex;
if (!removeEditor(editorIndex,true))
return;
}
}
PFolderNode parent = node->parent.lock();
if (parent) {
parent->children.removeAll(node);
}
}
2021-09-11 09:21:44 +08:00
void Project::updateFolderNode(PFolderNode node)
{
for (int i=0;i<node->children.count();i++){
PFolderNode child;
if (child->unitIndex<0) {
mFolders.append(getFolderPath(child));
updateFolderNode(child);
}
}
}
2021-09-11 11:42:20 +08:00
const QList<PProjectUnit> &Project::units() const
{
return mUnits;
}
2021-09-10 15:03:47 +08:00
const ProjectOptions &Project::options() const
{
return mOptions;
}
void Project::setOptions(const ProjectOptions &newOptions)
{
mOptions = newOptions;
}
2021-09-11 11:42:20 +08:00
const ProjectModel *Project::model() const
{
return &mModel;
}
2021-09-10 12:37:02 +08:00
const PFolderNode &Project::node() const
{
return mNode;
}
void Project::setNode(const PFolderNode &newNode)
{
mNode = newNode;
}
const QString &Project::name() const
{
return mName;
}
void Project::setName(const QString &newName)
{
mName = newName;
}
2021-09-09 18:36:54 +08:00
std::shared_ptr<QSettings> &Project::iniFile()
{
return mIniFile;
}
void Project::setIniFile(const std::shared_ptr<QSettings> &newIniFile)
{
mIniFile = newIniFile;
}
2021-09-09 00:15:12 +08:00
const QString &Project::filename() const
{
return mFilename;
}
2021-09-07 00:32:16 +08:00
ProjectUnit::ProjectUnit(Project* parent)
{
mEditor = nullptr;
mNode = nullptr;
mParent = parent;
2021-09-06 08:45:53 +08:00
}
2021-09-07 00:32:16 +08:00
Project *ProjectUnit::parent() const
2021-09-05 23:45:05 +08:00
{
return mParent;
}
2021-09-07 00:32:16 +08:00
void ProjectUnit::setParent(Project* newParent)
2021-09-05 23:45:05 +08:00
{
mParent = newParent;
}
Editor *ProjectUnit::editor() const
{
return mEditor;
}
void ProjectUnit::setEditor(Editor *newEditor)
{
mEditor = newEditor;
}
const QString &ProjectUnit::fileName() const
{
return mFileName;
}
void ProjectUnit::setFileName(const QString &newFileName)
{
mFileName = newFileName;
}
bool ProjectUnit::isNew() const
{
return mNew;
}
void ProjectUnit::setNew(bool newNew)
{
mNew = newNew;
}
const QString &ProjectUnit::folder() const
{
return mFolder;
}
void ProjectUnit::setFolder(const QString &newFolder)
{
mFolder = newFolder;
}
bool ProjectUnit::compile() const
{
return mCompile;
}
void ProjectUnit::setCompile(bool newCompile)
{
mCompile = newCompile;
}
bool ProjectUnit::compileCpp() const
{
return mCompileCpp;
}
void ProjectUnit::setCompileCpp(bool newCompileCpp)
{
mCompileCpp = newCompileCpp;
}
bool ProjectUnit::overrideBuildCmd() const
{
return mOverrideBuildCmd;
}
void ProjectUnit::setOverrideBuildCmd(bool newOverrideBuildCmd)
{
mOverrideBuildCmd = newOverrideBuildCmd;
}
const QString &ProjectUnit::buildCmd() const
{
return mBuildCmd;
}
void ProjectUnit::setBuildCmd(const QString &newBuildCmd)
{
mBuildCmd = newBuildCmd;
}
bool ProjectUnit::link() const
{
return mLink;
}
void ProjectUnit::setLink(bool newLink)
{
mLink = newLink;
}
int ProjectUnit::priority() const
{
return mPriority;
}
void ProjectUnit::setPriority(int newPriority)
{
mPriority = newPriority;
}
const QByteArray &ProjectUnit::encoding() const
{
return mEncoding;
}
void ProjectUnit::setEncoding(const QByteArray &newEncoding)
{
mEncoding = newEncoding;
}
2021-09-06 12:58:29 +08:00
bool ProjectUnit::modified() const
2021-09-05 23:45:05 +08:00
{
if (mEditor) {
return mEditor->modified();
} else {
return false;
}
}
void ProjectUnit::setModified(bool value)
{
// Mark the change in the coupled editor
if (mEditor) {
return mEditor->setModified(value);
}
// If modified is set to true, mark project as modified too
if (value) {
2021-09-07 10:28:40 +08:00
mParent->setModified(true);
2021-09-05 23:45:05 +08:00
}
}
bool ProjectUnit::save()
{
bool previous=pMainWindow->fileSystemWatcher()->blockSignals(true);
auto action = finally([&previous](){
pMainWindow->fileSystemWatcher()->blockSignals(previous);
});
bool result=true;
2021-09-07 10:28:40 +08:00
if (!mEditor && !fileExists(mFileName)) {
2021-09-05 23:45:05 +08:00
// file is neither open, nor saved
QStringList temp;
StringsToFile(temp,mFileName);
} else if (mEditor and modified()) {
result = mEditor->save();
}
2021-09-07 00:32:16 +08:00
if (mNode) {
2021-09-10 12:37:02 +08:00
mNode->text = extractFileName(mFileName);
2021-09-07 00:32:16 +08:00
}
2021-09-05 23:45:05 +08:00
return result;
}
2021-09-07 10:28:40 +08:00
PFolderNode &ProjectUnit::node()
{
return mNode;
}
void ProjectUnit::setNode(const PFolderNode &newNode)
{
mNode = newNode;
}
2021-09-11 09:21:44 +08:00
ProjectModel::ProjectModel(Project *project, QObject *parent):
QAbstractItemModel(parent),
mProject(project)
{
mUpdateCount = 0;
}
void ProjectModel::beginUpdate()
{
if (mUpdateCount==0)
beginResetModel();
mUpdateCount++;
}
void ProjectModel::endUpdate()
{
mUpdateCount--;
if (mUpdateCount==0)
endResetModel();
}
2021-09-11 11:42:20 +08:00
QModelIndex ProjectModel::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid()) {
return createIndex(row,column,mProject->node().get());
}
FolderNode* parentNode = static_cast<FolderNode*>(parent.internalPointer());
if (!parentNode) {
return QModelIndex();
}
return createIndex(row,column,parentNode->children[row].get());
}
QModelIndex ProjectModel::parent(const QModelIndex &child) const
{
if (!child.isValid())
return QModelIndex();
FolderNode * node = static_cast<FolderNode*>(child.internalPointer());
if (!node)
return QModelIndex();
PFolderNode parent = node->parent.lock();
if (!parent) // root node
return QModelIndex();
PFolderNode grand = parent->parent.lock();
if (!grand) {
return createIndex(0,0,parent.get());
}
int row = grand->children.indexOf(parent);
if (row<0)
return QModelIndex();
return createIndex(row,0,parent.get());
}
2021-09-11 09:21:44 +08:00
int ProjectModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid())
return 1;
FolderNode* p = static_cast<FolderNode*>(parent.internalPointer());
if (p) {
return p->children.count();
} else {
return mProject->node()->children.count();
}
}
int ProjectModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QVariant ProjectModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
FolderNode* p = static_cast<FolderNode*>(index.internalPointer());
if (!p)
return QVariant();
2021-09-11 11:42:20 +08:00
if (role == Qt::DisplayRole) {
return p->text;
2021-09-11 09:21:44 +08:00
}
2021-09-11 11:42:20 +08:00
return QVariant();
2021-09-11 09:21:44 +08:00
}