/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003 Yiannis An. Mandravellos
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL : http://www.codeblocks.org
*
* $Id: cbproject.cpp,v 1.54.2.1 2005/10/25 07:59:03 mandrav Exp $
* $Date: 2005/10/25 07:59:03 $
*/
#include "sdk_precomp.h"
#ifndef wxUSE_CHOICEDLG
#define wxUSE_CHOICEDLG 1
#endif
#include <wx/choicdlg.h>
#include "cbproject.h" // class's header file
#include "sdk_events.h"
#include "manager.h"
#include "projectoptionsdlg.h"
#include "projectloader.h"
#include "devcpploader.h"
#include "msvcloader.h"
#include "msvc7loader.h"
#include "projectlayoutloader.h"
#include "selecttargetdlg.h"
#include "globals.h"
#include "pluginmanager.h"
#include "projectmanager.h"
#include "messagemanager.h"
#include "editormanager.h"
#include "configmanager.h"
#include "filegroupsandmasks.h"
#include "compilerfactory.h"
#include "importers_globals.h"
// class constructor
cbProject::cbProject(const wxString& filename)
: m_ActiveTarget(-1),
m_DefaultExecuteTarget(-1),
m_Makefile(_T("")),
m_CustomMakefile(false),
m_Loaded(false),
m_CurrentlyLoading(false),
m_BasePath(_T(""))
{
SetCompilerIndex(CompilerFactory::GetDefaultCompilerIndex());
m_Files.Clear();
if (!filename.IsEmpty() && wxFileExists(filename))
{
// existing project
m_Filename = filename;
Open();
}
else
{
// new project
SetModified(true);
if (filename.IsEmpty())
{
m_Filename = CreateUniqueFilename();
m_Loaded = SaveAs();
}
else
{
m_Filename = filename;
m_Loaded = Save();
}
if (m_Loaded)
{
wxFileName fname(m_Filename);
m_Title = fname.GetName();
m_CommonTopLevelPath = GetBasePath() + wxFileName::GetPathSeparator();
NotifyPlugins(cbEVT_PROJECT_OPEN);
}
}
}
// class destructor
cbProject::~cbProject()
{
NotifyPlugins(cbEVT_PROJECT_CLOSE);
ClearAllProperties();
}
void cbProject::NotifyPlugins(wxEventType type)
{
CodeBlocksEvent event(type);
event.SetProject(this);
Manager::Get()->GetPluginManager()->NotifyPlugins(event);
}
void cbProject::SetCompilerIndex(int compilerIdx)
{
if(abs(compilerIdx)>=CompilerFactory::Compilers.GetCount())
return; // Invalid compiler
if (compilerIdx != m_CompilerIdx)
{
// update object filenames
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
if (target)
{
int count = GetFilesCount();
for (int i = 0; i < count; ++i)
{
ProjectFile* pf = GetFile(i);
wxFileName obj(pf->GetObjName());
if (FileTypeOf(pf->relativeFilename) != ftResource &&
obj.GetExt() == CompilerFactory::Compilers[m_CompilerIdx]->GetSwitches().objectExtension)
{
obj.SetExt(CompilerFactory::Compilers[compilerIdx]->GetSwitches().objectExtension);
pf->SetObjName(obj.GetFullName());
}
}
}
}
m_CompilerIdx = compilerIdx;
SetModified(true);
}
}
bool cbProject::GetModified()
{
if (CompileOptionsBase::GetModified())
return true;
// check targets
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
if (target->GetModified())
return true;
}
return false;
}
void cbProject::SetModified(bool modified)
{
CompileOptionsBase::SetModified(modified);
// modify targets
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
target->SetModified(modified);
}
}
void cbProject::SetMakefileCustom(bool custom)
{
if (m_CustomMakefile != custom)
{
m_CustomMakefile = custom;
SetModified(true);
}
}
wxString cbProject::CreateUniqueFilename()
{
const wxString prefix = _("Untitled");
wxString tmp;
ProjectsArray* arr = Manager::Get()->GetProjectManager()->GetProjects();
int projCount = arr->GetCount();
int iter = 1;
bool ok = false;
tmp << prefix << iter;
while (!ok)
{
tmp.Clear();
tmp << prefix << iter;
ok = true;
for (int i = 0; i < projCount; ++i)
{
cbProject* prj = arr->Item(i);
wxFileName fname(prj->GetFilename());
if (fname.GetName().Matches(tmp))
{
ok = false;
break;
}
}
if (ok)
break;
++iter;
}
return tmp << _T(".") << CODEBLOCKS_EXT;
}
void cbProject::ClearAllProperties()
{
m_Files.Clear();
m_CompilerOptions.Clear();
m_LinkerOptions.Clear();
m_IncludeDirs.Clear();
m_LibDirs.Clear();
while (m_Targets.GetCount())
{
ProjectBuildTarget* target = m_Targets[0];
delete target;
m_Targets.RemoveAt(0);
}
SetModified(true);
}
void cbProject::Open()
{
m_Loaded = false;
m_ProjectFilesMap.clear();
if (!wxFileName::FileExists(m_Filename))
{
wxString msg;
msg.Printf(_("Project '%s' does not exist..."), m_Filename.c_str());
wxMessageBox(msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
return;
}
bool fileUpgraded = false;
bool fileModified = false;
wxFileName fname(m_Filename);
FileType ft = FileTypeOf(m_Filename);
if (ft == ftCodeBlocksProject)
{
Manager::Get()->GetMessageManager()->AppendLog(_("Opening %s: "), m_Filename.c_str());
m_CurrentlyLoading = true;
ProjectLoader loader(this);
m_Loaded = loader.Open(m_Filename);
fileUpgraded = loader.FileUpgraded();
fileModified = loader.FileModified();
m_CurrentlyLoading = false;
}
else
{
Manager::Get()->GetMessageManager()->AppendLog(_("Importing %s: "), m_Filename.c_str());
IBaseLoader* loader = 0L;
switch (ft)
{
case ftDevCppProject: loader = new DevCppLoader(this); break;
case ftMSVCProject: loader = new MSVCLoader(this); break;
case ftMSVSProject: loader = new MSVC7Loader(this); break;
default: return;
}
int compilerIdx = -1;
if (ImportersGlobals::UseDefaultCompiler)
compilerIdx = CompilerFactory::GetDefaultCompilerIndex();
else
{
// select compiler for the imported project
// need to do it before actual import, because the importer might need
// project's compiler information (like the object files extension etc).
// first build a list of available compilers
wxString* comps = new wxString[CompilerFactory::Compilers.GetCount()];
for (unsigned int i = 0; i < CompilerFactory::Compilers.GetCount(); ++i)
{
comps[i] = CompilerFactory::Compilers[i]->GetName();
}
// now display a choice dialog
wxSingleChoiceDialog dlg(0,
_("Select compiler to use for the imported project"),
_("Select compiler for ") + wxFileName(m_Filename).GetFullName(),
CompilerFactory::Compilers.GetCount(),
comps);
dlg.SetSelection(CompilerFactory::GetDefaultCompilerIndex());
if (dlg.ShowModal() == wxID_OK)
compilerIdx = dlg.GetSelection();
}
if (compilerIdx != -1)
{
SetCompilerIndex(compilerIdx);
// actually import project file
m_CurrentlyLoading = true;
m_Loaded = loader->Open(m_Filename);
fname.SetExt(CODEBLOCKS_EXT);
m_Filename = fname.GetFullPath();
SetModified(true);
m_CurrentlyLoading = false;
}
else
m_Loaded = false;
delete loader;
}
if (m_Loaded)
{
CalculateCommonTopLevelPath();
Manager::Get()->GetMessageManager()->Log(_("done"));
if (!m_Targets.GetCount())
AddDefaultBuildTarget();
SetModified(ft != ftCodeBlocksProject || fileUpgraded || fileModified);
NotifyPlugins(cbEVT_PROJECT_OPEN);
if (fileUpgraded)
{
wxString msg;
msg.Printf(_("The project file of \"%s\" needs to be updated to the latest format.\n"
"This will happen automatically when you save the project."), m_Title.c_str());
wxMessageBox(msg, _("Information"), wxICON_INFORMATION);
}
}
else
Manager::Get()->GetMessageManager()->Log(_("failed"));
}
void cbProject::CalculateCommonTopLevelPath()
{
// find the common toplevel path
// for simple projects, this might be the path to the project file
// for projects where the project file is in a subdir, files will have ..
// in their paths
wxString sep = wxFileName::GetPathSeparator();
wxFileName base = GetBasePath() + sep;
Manager::Get()->GetMessageManager()->DebugLog(_("Project's base path: %s"), base.GetFullPath().c_str());
for (FilesList::Node* node = m_Files.GetFirst(); node; node = node->GetNext())
{
ProjectFile* f = node->GetData();
wxString tmp = f->relativeFilename;
wxFileName tmpbase = GetBasePath() + sep;
while (tmp.StartsWith(_T("..")))
{
tmpbase.AppendDir(_T(".."));
tmp.Remove(0, 2); // two dots
// remove separator(s) after dots
while (!tmp.IsEmpty() && (tmp.GetChar(0) == _T('/') || tmp.GetChar(0) == _T('\\')))
tmp.Remove(0, 1);
}
tmpbase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE);
if (tmpbase.GetDirCount() < base.GetDirCount())
base = tmpbase;
}
// update ProjectFiles info
for (FilesList::Node* node = m_Files.GetFirst(); node; node = node->GetNext())
{
ProjectFile* f = node->GetData();
wxFileName fname = f->file;
fname.MakeRelativeTo(base.GetFullPath());
f->relativeToCommonTopLevelPath = fname.GetFullPath();
f->SetObjName(f->relativeToCommonTopLevelPath);
}
m_CommonTopLevelPath = base.GetFullPath();
Manager::Get()->GetMessageManager()->DebugLog(_("Project's common toplevel path: %s"), m_CommonTopLevelPath.c_str());
}
wxString cbProject::GetCommonTopLevelPath()
{
return m_CommonTopLevelPath;
}
bool cbProject::SaveAs()
{
wxFileName fname;
fname.Assign(m_Filename);
wxFileDialog dlg(Manager::Get()->GetAppWindow(),
_("Save file"),
fname.GetPath(),
fname.GetFullName(),
CODEBLOCKS_FILES_FILTER,
wxSAVE | wxOVERWRITE_PROMPT);
if (dlg.ShowModal() != wxID_OK)
return false;
m_Filename = dlg.GetPath();
fname.Assign(m_Filename);
// make sure the project file uses the correct extension
// we don't use wxFileName::SetExt() because if the user has added a dot
// in the filename, the part after it would be interpeted as extension
// (and it might not be)
// so we just append the correct extension
if (!fname.GetExt().Matches(CODEBLOCKS_EXT))
fname.Assign(m_Filename + _T('.') + CODEBLOCKS_EXT);
// Manager::Get()->GetProjectManager()->GetTree()->SetItemText(m_ProjectNode, fname.GetFullName());
if (!m_Loaded)
AddDefaultBuildTarget();
ProjectLoader loader(this);
if (loader.Save(m_Filename))
{
NotifyPlugins(cbEVT_PROJECT_SAVE);
return true;
}
return false;
}
bool cbProject::Save()
{
if (m_Filename.IsEmpty())
return SaveAs();
ProjectLoader loader(this);
if (loader.Save(m_Filename))
{
NotifyPlugins(cbEVT_PROJECT_SAVE);
return true;
}
return false;
}
bool cbProject::SaveLayout()
{
if (m_Filename.IsEmpty())
return false;
wxFileName fname(m_Filename);
fname.SetExt(_T("layout"));
ProjectLayoutLoader loader(this);
return loader.Save(fname.GetFullPath());
}
bool cbProject::LoadLayout()
{
if (m_Filename.IsEmpty())
return false;
int openmode = ConfigManager::Get()->Read(_T("/project_manager/open_files"), (long int)1);
bool result = false;
if(openmode==2)
{
// Do not open any files
result = true;
}
else
{
Manager::Get()->GetEditorManager()->HideNotebook();
if(openmode == 0) // Open all files
{
FilesList::Node* node = m_Files.GetFirst();
while(node)
{
ProjectFile* f = node->GetData();
Manager::Get()->GetEditorManager()->Open(f->file.GetFullPath(),0,f);
node = node->GetNext();
}
result = true;
}
else if(openmode == 1)// Open last open files
{
wxFileName fname(m_Filename);
fname.SetExt(_T("layout"));
ProjectLayoutLoader loader(this);
if (loader.Open(fname.GetFullPath()))
{
FilesList::Node* node = m_Files.GetFirst();
while(node)
{
ProjectFile* f = node->GetData();
if (f->editorOpen)
{
cbEditor* ed = Manager::Get()->GetEditorManager()->Open(f->file.GetFullPath(),0,f);
if (ed)
ed->SetProjectFile(f);
}
node = node->GetNext();
}
ProjectFile* f = loader.GetTopProjectFile();
if (f)
{
Manager::Get()->GetMessageManager()->DebugLog(_T("Top Editor: %s"),f->file.GetFullPath().c_str());
EditorBase* eb = Manager::Get()->GetEditorManager()->Open(f->file.GetFullPath());
if(eb)
{
Manager::Get()->GetProjectManager()->SetTopEditor(eb);
eb->Activate();
}
}
Manager::Get()->GetAppWindow()->Thaw();
}
result = true;
}
else
result = false;
Manager::Get()->GetEditorManager()->ShowNotebook();
}
return result;
}
ProjectFile* cbProject::AddFile(const wxString& targetName, const wxString& filename, bool compile, bool link, unsigned short int weight)
{
int idx = IndexOfBuildTargetName(targetName);
return AddFile(idx, filename, compile, link, weight);
}
ProjectFile* cbProject::AddFile(int targetIndex, const wxString& filename, bool compile, bool link, unsigned short int weight)
{
// look if the file belongs to the project already. If so, return it
ProjectFile* f;
// NOTE (Rick#1#): When loading the project, do not search for existing files
// (Assumming that there are no duplicate entries in the .cbp file)
// This saves us a lot of processing when loading large projects.
// Remove the if to do the search anyway
// NOTE (mandrav#1#): We can't ignore that because even if we can rely on .cbp
// containing discrete files, we can't do that for imported projects...
// This means we have to search anyway.
// NP though, I added a hashmap for fast searches in GetFileByFilename()
f = GetFileByFilename(filename, true, true);
if (f)
return f;
f = GetFileByFilename(filename, false, true);
if (f)
return f;
// OK, add file
f = new ProjectFile;
bool localCompile, localLink;
wxFileName fname;
wxString ext;
f->project = this;
f->editorOpen = false;
f->editorPos = 0;
f->editorTopLine = 0;
f->useCustomBuildCommand = false;
f->autoDeps = true;
f->weight = weight;
fname = UnixFilename(filename);
ext = fname.GetExt().Lower();
if (ext.Matches(CPP_EXT) ||
ext.Matches(CXX_EXT))
f->compilerVar = _T("CPP");
else if (ext.Matches(C_EXT) ||
ext.Matches(CC_EXT))
f->compilerVar = _T("CC");
#ifdef __WXMSW__
else if (ext.Matches(RESOURCE_EXT))
f->compilerVar = _T("WINDRES");
#endif
if (!m_Targets.GetCount())
{
// no targets in project; add default
AddDefaultBuildTarget();
if (!m_Targets.GetCount())
{
delete f;
return 0L; // if that failed, fail addition of file...
}
}
if (targetIndex >= 0 && targetIndex < (int)m_Targets.GetCount())
f->AddBuildTarget(m_Targets[targetIndex]->GetTitle());
FileType ft = FileTypeOf(filename);
localCompile = compile &&
(ft == ftSource ||
ft == ftResource);
localLink = link &&
(ft == ftSource ||
ft == ftResource ||
ft == ftObject ||
ft == ftResourceBin ||
ft == ftStaticLib);
f->compile = localCompile;
f->link = localLink;
wxString fullFilename = UnixFilename(filename);
fname.Assign(fullFilename);
if(!m_CurrentlyLoading || m_BasePath.IsEmpty())
m_BasePath = GetBasePath();
fname.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, m_BasePath);
fullFilename = fname.GetFullPath();
fname.Assign(fullFilename);
f->file.Assign(fname);
//Manager::Get()->GetMessageManager()->Log(_T("Adding %s"), f->file.GetFullPath().c_str());
fname.MakeRelativeTo(m_BasePath);
f->relativeFilename = fname.GetFullPath();
m_Files.Append(f);
if (!m_CurrentlyLoading)
{
// check if we really need to recalculate the common top-level path for the project
if (!fullFilename.StartsWith(m_CommonTopLevelPath))
CalculateCommonTopLevelPath();
else
{
// set f->relativeToCommonTopLevelPath
f->relativeToCommonTopLevelPath = fullFilename.Right(fullFilename.Length() - m_CommonTopLevelPath.Length());
}
}
SetModified(true);
m_ProjectFilesMap[UnixFilename(f->relativeFilename)] = f; // add to hashmap
return f;
}
bool cbProject::RemoveFile(int index)
{
ProjectFile* f = m_Files[index];
m_ProjectFilesMap.erase(UnixFilename(f->relativeFilename)); // remove from hashmap
Manager::Get()->GetEditorManager()->Close(f->file.GetFullPath());
FilesList::Node* node = m_Files.Item(index);
m_Files.DeleteNode(node);
SetModified(true);
return true;
}
int filesSort(const ProjectFile** arg1, const ProjectFile** arg2)
{
return (*arg1)->file.GetFullPath().CompareTo((*arg2)->file.GetFullPath());
}
void cbProject::BuildTree(wxTreeCtrl* tree, const wxTreeItemId& root, bool categorize, bool useFolders, FilesGroupsAndMasks* fgam)
{
if (!tree)
return;
//sort list of files
m_Files.Sort(filesSort);
FileTreeData* ftd = new FileTreeData(this);
m_ProjectNode = tree->AppendItem(root, GetTitle(), 1, 1, ftd);
wxTreeItemId others = m_ProjectNode;
// create file-type categories nodes (if enabled)
wxTreeItemId* pGroupNodes = 0L;
if (categorize && fgam)
{
pGroupNodes = new wxTreeItemId[fgam->GetGroupsCount()];
for (unsigned int i = 0; i < fgam->GetGroupsCount(); ++i)
{
pGroupNodes[i] = tree->AppendItem(m_ProjectNode, fgam->GetGroupName(i), 3, 3);
}
// add a default category "Others" for all non-matching file-types
others = tree->AppendItem(m_ProjectNode, _("Others"), 3, 3);
}
// iterate all project files and add them to the tree
int count = 0;
for (FilesList::Node* node = m_Files.GetFirst(); node; node = node->GetNext())
{
ProjectFile* f = node->GetData();
ftd = new FileTreeData(this, count++);
wxTreeItemId parentNode = m_ProjectNode;
// check if files grouping is enabled and find the group parent
if (categorize && pGroupNodes && fgam)
{
bool found = false;
for (unsigned int i = 0; i < fgam->GetGroupsCount(); ++i)
{
wxFileName fname(f->relativeToCommonTopLevelPath);
if (fgam->MatchesMask(fname.GetFullName(), i))
{
parentNode = pGroupNodes[i];
found = true;
break;
}
}
// if not matched a group, put it in "Others" group
if (!found)
parentNode = others;
}
// add file in the tree
AddTreeNode(tree, f->relativeToCommonTopLevelPath, parentNode, useFolders, f->compile, ftd);
}
// remove empty tree nodes (like empty groups)
if (categorize && fgam)
{
for (unsigned int i = 0; i < fgam->GetGroupsCount(); ++i)
{
if (tree->GetChildrenCount(pGroupNodes[i], false) == 0)
tree->Delete(pGroupNodes[i]);
}
if (tree->GetChildrenCount(others, false) == 0)
tree->Delete(others);
}
delete[] pGroupNodes;
tree->Expand(m_ProjectNode);
}
void cbProject::AddTreeNode(wxTreeCtrl* tree, const wxString& text, const wxTreeItemId& parent, bool useFolders, bool compiles, FileTreeData* data)
{
// see if the text contains any path info, e.g. plugins/compilergcc/compilergcc.cpp
// in that case, take the first element (plugins in this example), create a sub-folder
// with the same name and recurse with the result...
wxString path = text;
int pos = path.Find(_T('/'));
if (pos == -1)
pos = path.Find(_T('\\'));
if (useFolders && pos >= 0)
{
// ok, we got it. now split it up and recurse
wxString folder = path.Left(pos);
path = path.Right(path.Length() - pos - 1);
// see if we already have this path
#if (wxMAJOR_VERSION == 2) && (wxMINOR_VERSION < 5)
long int cookie = 0;
#else
wxTreeItemIdValue cookie; //2.6.0
#endif
wxTreeItemId newparent = tree->GetFirstChild(parent, cookie);
while (newparent)
{
wxString itemText = tree->GetItemText(newparent);
if (itemText.Matches(folder))
break;
newparent = tree->GetNextChild(parent, cookie);
}
if (!newparent)
{
// in order not to override wxTreeCtrl to sort alphabetically but the
// folders be always on top, we just search here where to put the new folder...
#if (wxMAJOR_VERSION == 2) && (wxMINOR_VERSION < 5)
long int cookie2 = 0;
#else
wxTreeItemIdValue cookie2; //2.6.0
#endif
wxTreeItemId child = tree->GetFirstChild(parent, cookie2);
wxTreeItemId lastChild;
while (child)
{
if (tree->GetItemImage(child) == 3)
{
if (folder.CompareTo(tree->GetItemText(child)) < 0)
{
newparent = tree->InsertItem(parent, lastChild, folder, 3, 3);
break;
}
}
else
{
newparent = tree->PrependItem(parent, folder, 3, 3);
break;
}
lastChild = child;
child = tree->GetNextChild(parent, cookie2);
}
if (!newparent)
newparent = tree->AppendItem(parent, folder, 3, 3);
}
//tree->SortChildren(parent);
AddTreeNode(tree, path, newparent, true, compiles, data);
}
else
{
wxTreeItemId newnode = tree->AppendItem(parent, text, 2, 2, data);
// the following doesn't seem to work under wxMSW...
if (!compiles)
tree->SetItemTextColour(newnode, wxColour(0x80, 0x80, 0x80));
}
}
void cbProject::RenameInTree(const wxString &newname)
{
wxTreeCtrl* tree = Manager::Get()->GetProjectManager()->GetTree();
if(!tree || !m_ProjectNode)
return;
tree->SetItemText(m_ProjectNode, newname);
}
void cbProject::SaveTreeState(wxTreeCtrl* tree)
{
::SaveTreeState(tree, m_ProjectNode, m_ExpandedNodes);
}
void cbProject::RestoreTreeState(wxTreeCtrl* tree)
{
::RestoreTreeState(tree, m_ProjectNode, m_ExpandedNodes);
}
const wxString& cbProject::GetMakefile()
{
if (!m_Makefile.IsEmpty())
return m_Makefile;
wxFileName makefile(m_Makefile);
makefile.Assign(m_Filename);
makefile.SetName(_T("Makefile"));
makefile.SetExt(_T(""));
makefile.MakeRelativeTo(GetBasePath());
m_Makefile = makefile.GetFullPath();
SetModified(true);
return m_Makefile;
}
ProjectFile* cbProject::GetFile(int index)
{
FilesList::Node* node = m_Files.Item(index);
if (node)
return node->GetData();
return NULL;
}
ProjectFile* cbProject::GetFileByFilename(const wxString& filename, bool isRelative, bool isUnixFilename)
{
// m_ProjectFilesMap keeps UnixFilename(ProjectFile::relativeFilename)
wxString tmp = filename;
if (!isRelative)
{
// if the search is not relative, make it
wxFileName fname(filename);
fname.MakeRelativeTo(GetBasePath());
tmp = fname.GetFullPath();
}
else
{
// make sure filename doesn't start with ".\"
// our own relative files don't have it, so the search would fail
// this happens when importing MS projects...
if (tmp.StartsWith(_T(".\\")))
tmp.Remove(0, 2);
}
if (isUnixFilename)
return m_ProjectFilesMap[tmp];
return m_ProjectFilesMap[UnixFilename(tmp)];
}
bool cbProject::QueryCloseAllFiles()
{
FilesList::Node* node;
node = m_Files.GetFirst();
while(node)
{
ProjectFile* f = node->GetData();
cbEditor* ed = Manager::Get()->GetEditorManager()->IsBuiltinOpen(f->file.GetFullPath());
if (ed && ed->GetModified())
{
if (!Manager::Get()->GetEditorManager()->QueryClose(ed))
return false;
}
node = node->GetNext();
}
return true;
}
bool cbProject::CloseAllFiles(bool dontsave)
{
// first try to close modified editors
if(!dontsave)
if(!QueryCloseAllFiles())
return false;
// now free the rest of the project files
int count = m_Files.GetCount();
Manager::Get()->GetEditorManager()->HideNotebook();
FilesList::Node* node = m_Files.GetFirst();
while(node)
{
ProjectFile* f = node->GetData();
if (Manager::Get()->GetEditorManager()->Close(f->file.GetFullPath(),true))
{
FilesList::Node* oldNode = node;
node = node->GetNext();
m_Files.DeleteNode(oldNode);
--count;
}
else
node = node->GetNext();
}
Manager::Get()->GetEditorManager()->ShowNotebook();
return count == 0;
}
bool cbProject::SaveAllFiles()
{
int count = m_Files.GetCount();
FilesList::Node* node = m_Files.GetFirst();
while(node)
{
ProjectFile* f = node->GetData();
if (Manager::Get()->GetEditorManager()->Save(f->file.GetFullPath()))
--count;
node = node->GetNext();
}
return count == 0;
}
bool cbProject::ShowOptions()
{
ProjectOptionsDlg dlg(Manager::Get()->GetAppWindow(), this);
return dlg.ShowModal() == wxID_OK;
}
int cbProject::SelectTarget(int initial, bool evenIfOne)
{
if (!evenIfOne && GetBuildTargetsCount() == 1)
return 0;
SelectTargetDlg dlg(0L, this, initial);
if (dlg.ShowModal() == wxID_OK)
return dlg.GetSelection();
return -1;
}
// Build targets
ProjectBuildTarget* cbProject::AddDefaultBuildTarget()
{
return AddBuildTarget(_T("default"));
}
ProjectBuildTarget* cbProject::AddBuildTarget(const wxString& targetName)
{
ProjectBuildTarget* target = new ProjectBuildTarget(this);
target->m_Filename = m_Filename; // really important
target->SetTitle(targetName);
target->SetCompilerIndex(GetCompilerIndex()); // same compiler as project's
target->SetOutputFilename(GetOutputFilename());
target->SetWorkingDir(_T("."));
target->SetObjectOutput(_T(".objs"));
target->SetDepsOutput(_T(".deps"));
m_Targets.Add(target);
SetModified(true);
return target;
}
bool cbProject::RenameBuildTarget(int index, const wxString& targetName)
{
ProjectBuildTarget* target = GetBuildTarget(index);
if (target)
{
int count = GetFilesCount();
for (int i = 0; i < count; ++i)
{
ProjectFile* pf = GetFile(i);
pf->RenameBuildTarget(target->GetTitle(), targetName);
}
target->SetTitle(targetName);
SetModified(true);
return true;
}
return false;
}
bool cbProject::RenameBuildTarget(const wxString& oldTargetName, const wxString& newTargetName)
{
return RenameBuildTarget(IndexOfBuildTargetName(oldTargetName), newTargetName);
}
bool cbProject::RemoveBuildTarget(int index)
{
ProjectBuildTarget* target = GetBuildTarget(index);
if (target)
{
int count = GetFilesCount();
for (int i = 0; i < count; ++i)
{
ProjectFile* pf = GetFile(i);
pf->RemoveBuildTarget(target->GetTitle());
}
delete target;
m_Targets.RemoveAt(index);
SetModified(true);
return true;
}
return false;
}
bool cbProject::RemoveBuildTarget(const wxString& targetName)
{
return RemoveBuildTarget(IndexOfBuildTargetName(targetName));
}
int cbProject::IndexOfBuildTargetName(const wxString& targetName)
{
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
if (target->GetTitle().Matches(targetName))
return i;
}
return -1;
}
bool cbProject::SetActiveBuildTarget(int target)
{
if (target == m_ActiveTarget)
return true;
m_ActiveTarget = target;
SetModified(true);
return true;
}
int cbProject::GetActiveBuildTarget()
{
if (m_ActiveTarget < -1 || m_ActiveTarget >= (int)m_Targets.GetCount())
m_ActiveTarget = -1;
return m_ActiveTarget;
}
void cbProject::SetDefaultExecuteTargetIndex(int index)
{
if (m_DefaultExecuteTarget != index)
{
m_DefaultExecuteTarget = index;
SetModified(true);
}
}
int cbProject::GetDefaultExecuteTargetIndex()
{
if (m_DefaultExecuteTarget == -1)
{
// first-time: find the first target that provides executable...
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
if (target->GetTargetType() == ttExecutable ||
target->GetTargetType() == ttConsoleOnly)
{
m_DefaultExecuteTarget = i;
break;
}
}
}
return m_DefaultExecuteTarget;
}
ProjectBuildTarget* cbProject::GetBuildTarget(int index)
{
if (index >= 0 && index < (int)m_Targets.GetCount())
return m_Targets[index];
return 0L;
}
ProjectBuildTarget* cbProject::GetBuildTarget(const wxString& targetName)
{
int idx = IndexOfBuildTargetName(targetName);
return GetBuildTarget(idx);
}
void cbProject::ReOrderTargets(const wxArrayString& nameOrder)
{
MessageManager* msgMan = Manager::Get()->GetMessageManager();
if (nameOrder.GetCount() != m_Targets.GetCount())
{
msgMan->DebugLog(_("cbProject::ReOrderTargets() : Count does not match (%d sent, %d had)..."), nameOrder.GetCount(), m_Targets.GetCount());
return;
}
for (unsigned int i = 0; i < nameOrder.GetCount(); ++i)
{
ProjectBuildTarget* target = GetBuildTarget(nameOrder[i]);
if (!target)
{
msgMan->DebugLog(_("cbProject::ReOrderTargets() : Target \"%s\" not found..."), nameOrder[i].c_str());
break;
}
m_Targets.Remove(target);
m_Targets.Insert(target, i);
}
SetModified(true);
}
#ifdef USE_OPENFILES_TREE
bool MiscTreeItemData::OwnerCheck(wxTreeEvent& event,wxTreeCtrl *tree,wxEvtHandler *handler,bool strict)
{
if(!tree) // No tree to get data from - ignore event
return false;
MiscTreeItemData* data =
(MiscTreeItemData*)tree->GetItemData(event.GetItem());
if(!data)
{
if(!strict)
return true; // On doubt, allow event
else
{
event.Skip();
return false;
}
}
wxEvtHandler *h = data->GetOwner();
if((h && h!=handler) || (strict && !h))
{ // Tree Item belongs to another handler - skip
event.Skip();
return false;
}
return true;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1