Code::Blocks  SVN r11506
templatemanager.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 11432 $
6  * $Id: templatemanager.cpp 11432 2018-08-06 14:42:01Z ollydbg $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/templatemanager.cpp $
8  */
9 
10 #include "sdk_precomp.h"
11 
12 #ifndef CB_PRECOMP
13  #include <wx/intl.h>
14  #include <wx/menu.h>
15  #include <wx/filename.h>
16  #include <wx/msgdlg.h>
17  #include <wx/dir.h>
18 
19  #include "templatemanager.h"
20  #include "manager.h"
21  #include "configmanager.h"
22  #include "logmanager.h"
23  #include "projectmanager.h"
24  #include "cbproject.h"
25  #include "globals.h"
26  #include "compilerfactory.h"
27  #include "cbplugin.h"
28 #endif
29 
30 #include <wx/filedlg.h>
31 #include <wx/textdlg.h>
32 #include "filefilters.h"
33 #include "newfromtemplatedlg.h"
34 
35 template<> TemplateManager* Mgr<TemplateManager>::instance = nullptr;
36 template<> bool Mgr<TemplateManager>::isShutdown = false;
37 
39 {
40  //ctor
41  Manager::Get()->GetAppWindow()->PushEventHandler(this);
42 }
43 
45 {
46  //dtor
47 }
48 
49 void TemplateManager::CreateMenu(cb_unused wxMenuBar* menuBar)
50 {
51 }
52 
53 void TemplateManager::ReleaseMenu(cb_unused wxMenuBar* menuBar)
54 {
55 }
56 
58 {
59 }
60 
62 {
64  wxString baseDir = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T("UserTemplates");
65 
66  if (!wxDirExists(baseDir)) // avoid warnings in debug builds
67  return;
68 
69  wxDir dir(baseDir);
70  if (!dir.IsOpened())
71  return;
72 
73  wxString filename;
74  bool ok = dir.GetFirst(&filename, _T("*"), wxDIR_DIRS);
75  while (ok)
76  {
77  m_UserTemplates.Add(filename);
78  ok = dir.GetNext(&filename);
79  }
80 
81  Manager::Get()->GetLogManager()->DebugLog(F(_T("%d user templates loaded"), m_UserTemplates.GetCount()));
82 }
83 
85 {
86  cbProject* prj = NULL;
87 
89  NewFromTemplateDlg dlg(initial, m_UserTemplates);
90  PlaceWindow(&dlg);
91  if (dlg.ShowModal() == wxID_OK)
92  {
93  if (dlg.SelectedUserTemplate())
94  prj = NewProjectFromUserTemplate(dlg, pFilename);
95  else
96  prj = NewFromTemplate(dlg, pFilename);
97  }
98  return prj;
99 }
100 
102 {
103  cbProject* prj = NULL;
104  cbWizardPlugin* wiz = dlg.GetWizard();
105  if (wiz)
106  {
107  // wizard, too easy ;)
108  CompileTargetBase* ret = wiz->Launch(dlg.GetWizardIndex(), pFilename);
109  switch (wiz->GetOutputType(dlg.GetWizardIndex()))
110  {
111  case totProject: prj = dynamic_cast<cbProject*>(ret); break;
112  case totTarget: // fall-though
113  case totFiles: // fall-though
114  case totCustom: // fall-though
115  case totUser: // fall-though
116  default: break;
117  }
118  }
119  return prj;
120 }
121 
123 {
124  cbProject* prj = NULL;
125  if (!dlg.SelectedUserTemplate())
126  {
127  Manager::Get()->GetLogManager()->DebugLog(_T("TemplateManager::NewProjectFromUserTemplate() called when no user template was selected ?!?"));
128  return NULL;
129  }
130 
131  wxString path = Manager::Get()->GetConfigManager(_T("template_manager"))->Read(_T("/projects_path"));
133  // select directory to copy user template files
134  path = ChooseDirectory(nullptr, _("Choose a directory to create the new project"),
135  path, _T(""), false, true);
136  if (path.IsEmpty())
137  return NULL;
138  else if (path.Mid(path.Length() - 1) == wxFILE_SEP_PATH)
139  path.RemoveLast();
140 
141  // check for existing files; if found, notify about overwriting them
142  if (wxDirExists(path))
143  {
144  wxDir dir(path);
145  if (dir.HasFiles() || dir.HasSubDirs())
146  {
147  if (cbMessageBox(path + _(" already contains other files.\n"
148  "If you continue, files with the same names WILL BE OVERWRITTEN.\n"
149  "Are you sure you want to continue?"),
150  _("Files exist in directory"), wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT) != wxID_YES)
151  {
152  return nullptr;
153  }
154  }
155  }
156 
157  wxBusyCursor busy;
158 
159  wxString templ = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T("UserTemplates");
160  templ << sep << dlg.GetSelectedUserTemplate();
161  if (!wxDirExists(templ))
162  {
163  Manager::Get()->GetLogManager()->DebugLog(F(_T("Cannot open user-template source path '%s'!"), templ.wx_str()));
164  return NULL;
165  }
166 
167  // copy files
168  wxString project_filename;
169  wxArrayString files;
170  wxDir::GetAllFiles(templ, &files);
171  int count = 0;
172  int total_count = files.GetCount();
173  for (size_t i = 0; i < files.GetCount(); ++i)
174  {
175  wxFileName dstname(files[i]);
176  dstname.MakeRelativeTo(templ + sep);
177  wxString src = files[i];
178  wxString dst = path + sep + dstname.GetFullPath();
179 // Manager::Get()->GetLogManager()->DebugLog("dst=%s, dstname=%s", dst.c_str(), dstname.GetFullPath().c_str());
180  if (!CreateDirRecursively(dst))
181  Manager::Get()->GetLogManager()->DebugLog(_T("Failed creating directory for ") + dst);
182  if (wxCopyFile(src, dst, true))
183  {
184  if (FileTypeOf(dst) == ftCodeBlocksProject)
185  project_filename = dst;
186  ++count;
187  }
188  else
189  #if wxCHECK_VERSION(3, 0, 0)
190  Manager::Get()->GetLogManager()->DebugLog(F(_T("Failed copying %s to %s"), src.wx_str(), dst.wx_str()));
191  #else
192  Manager::Get()->GetLogManager()->DebugLog(F(_T("Failed copying %s to %s"), src.c_str(), dst.c_str()));
193  #endif
194  }
195  if (count != total_count)
196  cbMessageBox(_("Some files could not be loaded with the template..."), _("Error"), wxICON_ERROR);
197  else
198  {
199  // open new project
200  if (project_filename.IsEmpty())
201  cbMessageBox(_("User-template saved successfully but no project file exists in it!"));
202  else
203  {
204  // ask to rename the project file, if need be
205  wxFileName fname(project_filename);
206  wxString newname = cbGetTextFromUser(_("If you want, you can change the project's filename here (without extension):"), _("Change project's filename"), fname.GetName());
207  if (!newname.IsEmpty() && newname != fname.GetName())
208  {
209  fname.SetName(newname);
210  wxRenameFile(project_filename, fname.GetFullPath());
211  project_filename = fname.GetFullPath();
212  }
213  prj = Manager::Get()->GetProjectManager()->LoadProject(project_filename);
214  if (prj && !newname.IsEmpty())
215  {
216  prj->SetTitle(newname);
217  for (int i = 0; i < prj->GetBuildTargetsCount(); ++i)
218  {
219  ProjectBuildTarget* bt = prj->GetBuildTarget(i);
220  TargetFilenameGenerationPolicy tgfpPrefix, tgfpExtension;
221  bt->GetTargetFilenameGenerationPolicy(tgfpPrefix, tgfpExtension);
222  wxString outputFileName = bt->GetOutputFilename();
223  wxFileName outFname(outputFileName);
224  if (tgfpPrefix == tgfpPlatformDefault && bt->GetTargetType() == ttStaticLib)
225  {
226  Compiler* projectCompiler = CompilerFactory::GetCompiler(bt->GetCompilerID());
227  if (projectCompiler)
228  newname.Prepend(projectCompiler->GetSwitches().libPrefix);
229  }
230  outFname.SetName(newname);
231  bt->SetOutputFilename(outFname.GetFullPath());
232  }
233  Manager::Get()->GetProjectManager()->GetUI().RebuildTree(); // so the tree shows the new name
234  CodeBlocksEvent evt(cbEVT_PROJECT_OPEN, 0, prj);
235  Manager::Get()->ProcessEvent(evt);
236  }
237  }
238  }
239  if (prj && pFilename)
240  *pFilename = prj->GetFilename();
241  return prj;
242 }
243 
245 {
246  if (!prj)
247  return;
248 
249  // save project & all files
250  if (!prj->SaveAllFiles() ||
251  !prj->Save())
252  {
253  cbMessageBox(_("Could not save project and/or all its files. Aborting..."), _("Error"), wxICON_ERROR);
254  return;
255  }
256 
257  // create destination dir
258  wxString templ = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + _T("UserTemplates");
259  if (!CreateDirRecursively(templ, 0755))
260  {
261  cbMessageBox(_("Couldn't create directory for user templates:\n") + templ, _("Error"), wxICON_ERROR);
262  return;
263  }
264 
265  // get default template title
266  wxString title = prj->GetTitle();
267 
268  // filter title, removing all illegal filename characters
269  wxFileName titleFileName(title) ;
270  wxString forbidden = titleFileName.GetForbiddenChars();
271  for (size_t i=0; i<forbidden.Length(); ++i)
272  title.Replace(wxString(forbidden[i]), wxT(""), true);
273 
274  // check if it exists and ask a different title
275  while (true)
276  {
277  // ask for template title (unique)
278  wxTextEntryDialog dlg(nullptr, _("Enter a title for this template"), _("Enter title"), title);
279  PlaceWindow(&dlg);
280  if (dlg.ShowModal() != wxID_OK)
281  return;
282 
283  title = dlg.GetValue();
284  if (!wxDirExists(templ + wxFILE_SEP_PATH + title))
285  {
286  templ << wxFILE_SEP_PATH << title;
287  wxMkdir(templ, 0755);
288  break;
289  }
290  else
291  cbMessageBox(_("You have another template with the same title.\nPlease choose another title..."));
292  }
293 
294  wxBusyCursor busy;
295 
296  // copy project and all files to destination dir
297  int count = 0;
298  int total_count = prj->GetFilesCount();
299  templ << wxFILE_SEP_PATH;
300  wxFileName fname;
301 
302  for (FilesList::iterator it = prj->GetFilesList().begin(); it != prj->GetFilesList().end(); ++it)
303  {
304  wxString src = (*it)->file.GetFullPath();
305  wxString dst = templ + (*it)->relativeToCommonTopLevelPath;
306  #if wxCHECK_VERSION(3, 0, 0)
307  Manager::Get()->GetLogManager()->DebugLog(F(_T("Copying %s to %s"), src.wx_str(), dst.wx_str()));
308  #else
309  Manager::Get()->GetLogManager()->DebugLog(F(_T("Copying %s to %s"), src.c_str(), dst.c_str()));
310  #endif
311  if (!CreateDirRecursively(dst))
312  Manager::Get()->GetLogManager()->DebugLog(_T("Failed creating directory for ") + dst);
313  if (wxCopyFile(src, dst, true))
314  ++count;
315  else
316  #if wxCHECK_VERSION(3, 0, 0)
317  Manager::Get()->GetLogManager()->DebugLog(F(_T("Failed copying %s to %s"), src.wx_str(), dst.wx_str()));
318  #else
319  Manager::Get()->GetLogManager()->DebugLog(F(_T("Failed copying %s to %s"), src.c_str(), dst.c_str()));
320  #endif
321  }
322 
323  // cbProject doesn't have a GetRelativeToCommonTopLevelPath() function, so we simulate it here
324  // to find out the real destination file to create...
325  wxString topLevelPath = prj->GetCommonTopLevelPath();
326  fname.Assign(prj->GetFilename());
327  fname.MakeRelativeTo(topLevelPath);
328  fname.Assign(templ + fname.GetFullPath());
329  if (!CreateDirRecursively(fname.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), 0755))
330  {
331  cbMessageBox(_("Failed to create the directory for the project file!"), _("Error"), wxICON_ERROR);
332  ++count;
333  }
334  else
335  {
336  if (!wxCopyFile(prj->GetFilename(), fname.GetFullPath()))
337  {
338  Manager::Get()->GetLogManager()->DebugLog(_T("Failed to copy the project file: ") + fname.GetFullPath());
339  cbMessageBox(_("Failed to copy the project file!"), _("Error"), wxICON_ERROR);
340  ++count;
341  }
342  }
343 
344  if (count == total_count)
345  cbMessageBox(_("User-template saved successfully"), _("Information"), wxICON_INFORMATION | wxOK);
346  else
347  cbMessageBox(_("Some files could not be saved with the template..."), _("Error"), wxICON_ERROR);
348 }
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
cbProject * NewFromTemplate(NewFromTemplateDlg &dlg, wxString *pFilename=nullptr)
virtual void GetTargetFilenameGenerationPolicy(TargetFilenameGenerationPolicy &prefixOut, TargetFilenameGenerationPolicy &extensionOut) const
~TemplateManager() override
bool wxRenameFile(const wxString &file1, const wxString &file2, bool overwrite=true)
TargetFilenameGenerationPolicy
A target&#39;s filename can either be auto-generated based on the running platform, or completely specifi...
void Assign(const wxFileName &filepath)
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
virtual void RebuildTree()=0
Rebuild the project manager&#39;s tree.
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
bool IsOpened() const
bool SelectedUserTemplate() const
bool GetFirst(wxString *filename, const wxString &filespec=wxEmptyString, int flags=wxDIR_DEFAULT) const
#define wxICON_ERROR
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
Definition: cbproject.h:685
wxString GetSelectedUserTemplate() const
DLLIMPORT wxString cbGetTextFromUser(const wxString &message, const wxString &caption=cbGetTextFromUserPromptStr, const wxString &default_value=wxEmptyString, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord, bool centre=true)
Definition: globals.cpp:1465
void CreateMenu(wxMenuBar *menuBar)
DLLIMPORT wxString ChooseDirectory(wxWindow *parent, const wxString &message=_("Select directory"), const wxString &initialPath=_T(""), const wxString &basePath=_T(""), bool askToMakeRelative=false, bool showCreateDirButton=false)
Definition: globals.cpp:639
size_t Length() const
wxCStrData c_str() const
bool wxDirExists(const wxString &dirname)
static Compiler * GetCompiler(size_t index)
Generate filename based on running platform defaults.
#define wxNO_DEFAULT
#define _T(string)
bool HasSubDirs(const wxString &dirspec=wxEmptyString) const
int GetWizardIndex() const
#define wxYES_NO
cbProjectManagerUI & GetUI()
DLLIMPORT FileType FileTypeOf(const wxString &filename)
Definition: globals.cpp:285
#define wxICON_INFORMATION
wxString GetName() const
static size_t GetAllFiles(const wxString &dirname, wxArrayString *files, const wxString &filespec=wxEmptyString, int flags=wxDIR_DEFAULT)
#define wxT(string)
bool wxMkdir(const wxString &dir, int perm=wxS_DIR_DEFAULT)
A generic Code::Blocks event.
Definition: sdk_events.h:20
virtual wxString GetOutputFilename()
Read the target&#39;s output filename.
cbProject * NewProjectFromUserTemplate(NewFromTemplateDlg &dlg, wxString *pFilename=nullptr)
wxWindow * GetAppWindow() const
Definition: manager.cpp:424
#define wxICON_EXCLAMATION
template produces custom output (entirely up to the wizard used)
Definition: globals.h:150
virtual TargetType GetTargetType() const
Read the target&#39;s type.
virtual CompileTargetBase * Launch(int index, wxString *createdFilename=nullptr)=0
When this is called, the wizard must get to work ;).
cbWizardPlugin * GetWizard()
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
bool MakeRelativeTo(const wxString &pathBase=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
template outputs a new file (or files)
Definition: globals.h:149
Represents a Code::Blocks project.
Definition: cbproject.h:96
virtual const wxString & GetFilename() const
wxString & RemoveLast(size_t n=1)
static wxString GetConfigFolder()
cbProject * LoadProject(const wxString &filename, bool activateIt=true)
Load a project from disk.
virtual void SetOutputFilename(const wxString &filename)
Set the target&#39;s output filename.
virtual const wxString & GetTitle() const
Read the target&#39;s title.
cbProject * New(TemplateOutputType initial=totProject, wxString *pFilename=nullptr)
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
static const wxString sep
LogManager * GetLogManager() const
Definition: manager.cpp:439
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
bool wxCopyFile(const wxString &file1, const wxString &file2, bool overwrite=true)
static wxUniChar GetPathSeparator(wxPathFormat format=wxPATH_NATIVE)
const wxStringCharType * wx_str() const
virtual int ShowModal()
#define wxOK
virtual TemplateOutputType GetOutputType(int index) const =0
void SaveUserTemplate(cbProject *prj)
void ReleaseMenu(wxMenuBar *menuBar)
bool SaveAllFiles()
Save all project files.
Definition: cbproject.cpp:1117
Definition: manager.h:183
int GetFilesCount()
Definition: cbproject.h:142
void BuildToolsMenu(wxMenu *menu)
const wxString & _(const wxString &string)
int GetBuildTargetsCount()
Definition: cbproject.h:200
TemplateOutputType
Template output types.
Definition: globals.h:145
wxArrayString m_UserTemplates
Target produces a static library.
ProjectBuildTarget * GetBuildTarget(int index)
Access a build target.
Definition: cbproject.cpp:1392
Abstract base class for compilers.
Definition: compiler.h:274
static wxString GetForbiddenChars(wxPathFormat format=wxPATH_NATIVE)
wxString libPrefix
Definition: compiler.h:223
bool GetNext(wxString *filename) const
bool IsEmpty() const
DLLIMPORT void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode=pdlBest, bool enforce=false)
Definition: globals.cpp:1177
wxString GetPath(int flags=wxPATH_GET_VOLUME, wxPathFormat format=wxPATH_NATIVE) const
virtual const wxString & GetCompilerID() const
Read the target&#39;s compiler.
void DebugLog(const wxString &msg, Logger::level lv=Logger::info)
Definition: logmanager.h:146
template adds a new target in a project
Definition: globals.h:148
virtual const CompilerSwitches & GetSwitches() const
Get the compiler&#39;s generic switches.
Definition: compiler.h:301
bool ProcessEvent(CodeBlocksEvent &event)
Definition: manager.cpp:246
wxString GetCommonTopLevelPath() const
Definition: cbproject.cpp:423
wxString & Prepend(const wxString &str)
EVTIMPORT const wxEventType cbEVT_PROJECT_OPEN
Definition: sdk_events.cpp:97
size_t Add(const wxString &str, size_t copies=1)
template is a user-saved project template
Definition: globals.h:151
void SetTitle(const wxString &title) override
Changes project title.
Definition: cbproject.cpp:1650
Represents a Code::Blocks project build target.
bool HasFiles(const wxString &filespec=wxEmptyString) const
size_t GetCount() const
template outputs a new project
Definition: globals.h:147
DLLIMPORT bool CreateDirRecursively(const wxString &full_path, int perms=0755)
Definition: globals.cpp:610
Base class for wizard plugins.
Definition: cbplugin.h:967
void SetName(const wxString &name)
bool Save()
Save the project.
Definition: cbproject.cpp:482
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
#define NULL
Definition: prefix.cpp:59
wxString Mid(size_t first, size_t nCount=wxString::npos) const
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395
Base class for build target classes Each Code::Blocks project consists of at least one target...