/*
* 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: templatemanager.cpp,v 1.23.2.1 2005/10/25 07:59:03 mandrav Exp $
* $Date: 2005/10/25 07:59:03 $
*/
#include "sdk_precomp.h"
#include <wx/mdi.h>
#include <wx/intl.h>
#include <wx/dir.h>
#include <wx/menu.h>
#include <wx/log.h>
#include <wx/filedlg.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include "templatemanager.h"
#include "manager.h"
#include "configmanager.h"
#include "messagemanager.h"
#include "projectmanager.h"
#include "cbproject.h"
#include "globals.h"
#include "managerproxy.h"
#include "compilerfactory.h"
int idMenuNewFromTemplate = wxNewId();
TemplateManager* TemplateManager::Get()
{
if (!TemplateManagerProxy::Get())
{
TemplateManagerProxy::Set( new TemplateManager );
Manager::Get()->GetMessageManager()->Log(_("TemplateManager initialized"));
}
return TemplateManagerProxy::Get();
}
void TemplateManager::Free()
{
if (TemplateManagerProxy::Get())
{
delete TemplateManagerProxy::Get();
TemplateManagerProxy::Set( 0L );
}
}
BEGIN_EVENT_TABLE(TemplateManager, wxEvtHandler)
EVT_MENU(idMenuNewFromTemplate, TemplateManager::OnNew)
END_EVENT_TABLE()
TemplateManager::TemplateManager()
{
//ctor
Manager::Get()->GetAppWindow()->PushEventHandler(this);
}
TemplateManager::~TemplateManager()
{
//dtor
// this is a core manager, so it is removed when the app is shutting down.
// in this case, the app has already un-hooked us, so no need to do it ourselves...
// Manager::Get()->GetAppWindow()->RemoveEventHandler(this);
WX_CLEAR_ARRAY(m_Templates);
}
void TemplateManager::CreateMenu(wxMenuBar* menuBar)
{
}
void TemplateManager::ReleaseMenu(wxMenuBar* menuBar)
{
}
void TemplateManager::BuildToolsMenu(wxMenu* menu)
{
if (menu)
menu->Append(idMenuNewFromTemplate, _("&From template..."));
}
void TemplateManager::LoadTemplates()
{
wxLogNull zero; // disable error logging
wxString baseDir = ConfigManager::Get()->Read(_T("/data_path"));
baseDir << _T("/templates");
wxDir dir(baseDir);
if (!dir.IsOpened())
return;
WX_CLEAR_ARRAY(m_Templates);
wxString filename;
bool ok = dir.GetFirst(&filename, _T("*.template"), wxDIR_FILES);
while (ok)
{
ProjectTemplateLoader* pt = new ProjectTemplateLoader();
if (pt->Open(baseDir + _T("/") + filename))
m_Templates.Add(pt);
else
delete pt;
ok = dir.GetNext(&filename);
}
Manager::Get()->GetMessageManager()->DebugLog(_("%d templates loaded"), m_Templates.GetCount());
}
void TemplateManager::LoadUserTemplates()
{
wxLogNull zero; // disable error logging
m_UserTemplates.Clear();
wxString baseDir = wxGetHomeDir();
baseDir << _T("/.CodeBlocks");
wxDir dir(baseDir);
if (!dir.IsOpened())
return;
wxString filename;
bool ok = dir.GetFirst(&filename, _T("*"), wxDIR_DIRS);
while (ok)
{
m_UserTemplates.Add(filename);
ok = dir.GetNext(&filename);
}
Manager::Get()->GetMessageManager()->DebugLog(_("%d user templates loaded"), m_UserTemplates.GetCount());
}
void TemplateManager::NewProject()
{
// one-time warning message
if (ConfigManager::Get()->Read(_T("/template_manager/notification"), 1L) == 1)
{
wxMessageBox(_("These templates are only provided for your convenience.\n"
"Many of the available templates need extra libraries "
"in order to be compiled succesfuly.\n\n"
"Extra libraries which Code::Blocks does *NOT* provide..."),
_("One-time information"),
wxICON_INFORMATION);
// don't warn the user again
ConfigManager::Get()->Write(_T("/template_manager/notification"), 0L);
}
LoadTemplates();
LoadUserTemplates();
NewFromTemplateDlg dlg(m_Templates, m_UserTemplates);
if (dlg.ShowModal() == wxID_OK)
{
if (dlg.SelectedUserTemplate())
NewProjectFromUserTemplate(dlg);
else
NewProjectFromTemplate(dlg);
}
}
void TemplateManager::NewProjectFromTemplate(NewFromTemplateDlg& dlg)
{
// is it a wizard or a template?
cbProjectWizardPlugin* wiz = dlg.GetWizard();
if (wiz)
{
// wizard, too easy ;)
wiz->Launch();
return;
}
// else it's a template
ProjectTemplateLoader* pt = dlg.GetTemplate();
if (!pt)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Templates dialog returned OK but no template was selected ?!?"));
return;
}
int optidx = dlg.GetOptionIndex();
int filesetidx = dlg.GetFileSetIndex();
TemplateOption& option = pt->m_TemplateOptions[optidx];
FileSet& fileset = pt->m_FileSets[filesetidx];
wxString baseDir = ConfigManager::Get()->Read(_T("/data_path"));
wxFileDialog fdlg(0L,
_("Save project"),
wxEmptyString,
pt->m_Name,
CODEBLOCKS_FILES_FILTER,
wxSAVE | wxOVERWRITE_PROMPT);
if (fdlg.ShowModal() != wxID_OK)
return;
wxFileName fname;
fname.Assign(fdlg.GetPath());
// 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(fdlg.GetPath() + _T('.') + CODEBLOCKS_EXT);
wxString path = fname.GetPath(wxPATH_GET_VOLUME);
wxString filename = fname.GetFullPath();
wxString sep = wxFileName::GetPathSeparator();
baseDir << sep << _T("templates");
wxCopyFile(baseDir + sep + option.file, filename);
cbProject* prj = Manager::Get()->GetProjectManager()->LoadProject(filename);
if (prj)
{
if (!dlg.DoNotCreateFiles())
{
for (unsigned int i = 0; i < fileset.files.GetCount(); ++i)
{
FileSetFile& fsf = fileset.files[i];
wxString dst = path + sep + fsf.destination;
bool skipped = false;
while (wxFileExists(dst))
{
wxString msg;
msg.Printf(_("File %s already exists.\nDo you really want to overwrite this file?"), dst.c_str());
if (wxMessageBox(msg, _("Overwrite existing file?"), wxYES_NO | wxICON_WARNING) == wxYES)
break;
wxFileDialog fdlg(0L,
_("Save file as..."),
wxEmptyString,
dst,
SOURCE_FILES_FILTER,
wxSAVE);
if (fdlg.ShowModal() == wxID_CANCEL)
{
msg.Printf(_("File %s is skipped..."), dst.c_str());
wxMessageBox(msg, _("File skipped"), wxICON_ERROR);
skipped = true;
break;
}
dst = fdlg.GetPath();
}
if (skipped)
continue;
wxCopyFile(baseDir + sep + fsf.source, dst);
prj->AddFile(0, dst);
}
}
for (unsigned int i = 0; i < option.extraCFlags.GetCount(); ++i)
prj->AddCompilerOption(option.extraCFlags[i]);
for (unsigned int i = 0; i < option.extraLDFlags.GetCount(); ++i)
prj->AddLinkerOption(option.extraLDFlags[i]);
Manager::Get()->GetProjectManager()->RebuildTree();
if (!pt->m_Notice.IsEmpty())
wxMessageBox(pt->m_Notice, _("Notice"), pt->m_NoticeMsgType);
if (!option.notice.IsEmpty())
wxMessageBox(option.notice, _("Notice"), option.noticeMsgType);
}
}
void TemplateManager::NewProjectFromUserTemplate(NewFromTemplateDlg& dlg)
{
if (!dlg.SelectedUserTemplate())
{
Manager::Get()->GetMessageManager()->DebugLog(_("TemplateManager::NewProjectFromUserTemplate() called when no user template was selected ?!?"));
return;
}
// select directory to copy user template files
wxString sep = wxFileName::GetPathSeparator();
wxString path = ChooseDirectory(0, _("Choose a directory to create the new project"));
if (path.IsEmpty())
return;
wxBusyCursor busy;
wxString templ = wxGetHomeDir();
templ << sep << _T(".CodeBlocks") << sep << dlg.GetSelectedUserTemplate();
if (!wxDirExists(templ))
{
Manager::Get()->GetMessageManager()->DebugLog(_("Cannot open user-template source path '%s'!"), templ.c_str());
return;
}
// copy files
wxString project_filename;
wxArrayString files;
wxDir::GetAllFiles(templ, &files);
int count = 0;
int total_count = files.GetCount();
for (size_t i = 0; i < files.GetCount(); ++i)
{
wxFileName dstname(files[i]);
dstname.MakeRelativeTo(templ + sep);
wxString src = files[i];
wxString dst = path + sep + dstname.GetFullPath();
// Manager::Get()->GetMessageManager()->DebugLog("dst=%s, dstname=%s", dst.c_str(), dstname.GetFullPath().c_str());
if (!CreateDirRecursively(dst))
Manager::Get()->GetMessageManager()->DebugLog(_("Failed creating directory for %s"), dst.c_str());
if (wxCopyFile(src, dst, true))
{
if (FileTypeOf(dst) == ftCodeBlocksProject)
project_filename = dst;
++count;
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Failed copying %s to %s"), src.c_str(), dst.c_str());
}
if (count != total_count)
wxMessageBox(_("Some files could not be loaded with the template..."), _("Error"), wxICON_ERROR);
else
{
// open new project
if (project_filename.IsEmpty())
wxMessageBox(_("User-template saved succesfuly but no project file exists in it!"));
else
{
// ask to rename the project file, if need be
wxFileName fname(project_filename);
wxString newname = wxGetTextFromUser(_("If you want, you can change the project's filename here (without extension):"), _("Change project's filename"), fname.GetName());
if (!newname.IsEmpty() && newname != fname.GetName())
{
fname.SetName(newname);
wxRenameFile(project_filename, fname.GetFullPath());
project_filename = fname.GetFullPath();
}
Manager::Get()->GetProjectManager()->LoadProject(project_filename);
}
}
}
void TemplateManager::SaveUserTemplate(cbProject* prj)
{
if (!prj)
return;
// save project & all files
if (!prj->SaveAllFiles() ||
!prj->Save())
{
wxMessageBox(_("Could not save project and/or all its files. Aborting..."), _("Error"), wxICON_ERROR);
return;
}
// create destination dir
wxString templ = wxGetHomeDir();
templ << _T("/.CodeBlocks");
if (!wxDirExists(templ))
wxMkdir(templ, 0755);
// check if it exists and ask a different title
wxString title = prj->GetTitle();
while (true)
{
// ask for template title (unique)
wxTextEntryDialog dlg(0, _("Enter a title for this template"), _("Enter title"), title);
if (dlg.ShowModal() != wxID_OK)
return;
title = dlg.GetValue();
if (!wxDirExists(templ + _T("/") + title))
{
templ << _T("/") << title;
wxMkdir(templ, 0755);
break;
}
else
wxMessageBox(_("You have another template with the same title.\nPlease choose another title..."));
}
wxBusyCursor busy;
// copy project and all files to destination dir
int count = 0;
int total_count = prj->GetFilesCount();
templ << _T("/");
wxFileName fname;
for (int i = 0; i < total_count; ++i)
{
wxString src = prj->GetFile(i)->file.GetFullPath();
wxString dst = templ + prj->GetFile(i)->relativeFilename;
// Manager::Get()->GetMessageManager()->DebugLog(_("Copying %s to %s"), src.c_str(), dst.c_str());
if (!CreateDirRecursively(dst))
Manager::Get()->GetMessageManager()->DebugLog(_("Failed creating directory for %s"), dst.c_str());
if (wxCopyFile(src, dst, true))
++count;
else
Manager::Get()->GetMessageManager()->DebugLog(_("Failed copying %s to %s"), src.c_str(), dst.c_str());
}
fname.Assign(prj->GetFilename());
if (!wxCopyFile(prj->GetFilename(), templ + fname.GetFullName()))
wxMessageBox(_("Failed to copy the project file!"), _("Error"), wxICON_ERROR);
if (count == total_count)
wxMessageBox(_("User-template saved succesfuly"));
else
wxMessageBox(_("Some files could not be saved with the template..."), _("Error"), wxICON_ERROR);
}
// events
void TemplateManager::OnNew(wxCommandEvent& event)
{
NewProject();
}
syntax highlighted by Code2HTML, v. 0.9.1