/* * 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 * 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 #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