mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-12 08:24:38 +02:00
1218 lines
38 KiB
C++
1218 lines
38 KiB
C++
// This file is part of Notepad++ project
|
|
// Copyright (C)2003 Don HO <don.h@free.fr>
|
|
//
|
|
// 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.
|
|
//
|
|
// Note that the GPL places important restrictions on "derived works", yet
|
|
// it does not provide a detailed definition of that term. To avoid
|
|
// misunderstandings, we consider an application to constitute a
|
|
// "derivative work" for the purpose of this license if it does any of the
|
|
// following:
|
|
// 1. Integrates source code from Notepad++.
|
|
// 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
|
|
// installer, such as those produced by InstallShield.
|
|
// 3. Links to a library or executes a program that does any of the above.
|
|
//
|
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
#include "ProjectPanel.h"
|
|
#include "resource.h"
|
|
#include "tinyxml.h"
|
|
#include "FileDialog.h"
|
|
#include "localization.h"
|
|
#include "Parameters.h"
|
|
|
|
#define CX_BITMAP 16
|
|
#define CY_BITMAP 16
|
|
|
|
#define INDEX_CLEAN_ROOT 0
|
|
#define INDEX_DIRTY_ROOT 1
|
|
#define INDEX_PROJECT 2
|
|
#define INDEX_OPEN_NODE 3
|
|
#define INDEX_CLOSED_NODE 4
|
|
#define INDEX_LEAF 5
|
|
#define INDEX_LEAF_INVALID 6
|
|
|
|
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
|
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
|
|
|
INT_PTR CALLBACK ProjectPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG :
|
|
{
|
|
ProjectPanel::initMenus();
|
|
|
|
// Create toolbar menu
|
|
int style = WS_CHILD | WS_VISIBLE | CCS_ADJUSTABLE | TBSTYLE_AUTOSIZE | TBSTYLE_FLAT | TBSTYLE_LIST;
|
|
_hToolbarMenu = CreateWindowEx(0,TOOLBARCLASSNAME,NULL, style,
|
|
0,0,0,0,_hSelf,(HMENU)0, _hInst, NULL);
|
|
TBBUTTON tbButtons[2];
|
|
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
generic_string workspace_entry = pNativeSpeaker->getProjectPanelLangMenuStr("Entries", 0, PM_WORKSPACEMENUENTRY);
|
|
generic_string edit_entry = pNativeSpeaker->getProjectPanelLangMenuStr("Entries", 1, PM_EDITMENUENTRY);
|
|
|
|
tbButtons[0].idCommand = IDB_PROJECT_BTN;
|
|
tbButtons[0].iBitmap = I_IMAGENONE;
|
|
tbButtons[0].fsState = TBSTATE_ENABLED;
|
|
tbButtons[0].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
|
|
tbButtons[0].iString = (INT_PTR)workspace_entry.c_str();
|
|
|
|
tbButtons[1].idCommand = IDB_EDIT_BTN;
|
|
tbButtons[1].iBitmap = I_IMAGENONE;
|
|
tbButtons[1].fsState = TBSTATE_ENABLED;
|
|
tbButtons[1].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
|
|
tbButtons[1].iString = (INT_PTR)edit_entry.c_str();
|
|
|
|
SendMessage(_hToolbarMenu, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
SendMessage(_hToolbarMenu, TB_ADDBUTTONS, (WPARAM)sizeof(tbButtons) / sizeof(TBBUTTON), (LPARAM)&tbButtons);
|
|
SendMessage(_hToolbarMenu, TB_AUTOSIZE, 0, 0);
|
|
ShowWindow(_hToolbarMenu, SW_SHOW);
|
|
|
|
_treeView.init(_hInst, _hSelf, ID_PROJECTTREEVIEW);
|
|
|
|
setImageList(IDI_PROJECT_WORKSPACE, IDI_PROJECT_WORKSPACEDIRTY, IDI_PROJECT_PROJECT, IDI_PROJECT_FOLDEROPEN, IDI_PROJECT_FOLDERCLOSE, IDI_PROJECT_FILE, IDI_PROJECT_FILEINVALID);
|
|
_treeView.addCanNotDropInList(INDEX_LEAF);
|
|
_treeView.addCanNotDropInList(INDEX_LEAF_INVALID);
|
|
|
|
_treeView.addCanNotDragOutList(INDEX_CLEAN_ROOT);
|
|
_treeView.addCanNotDragOutList(INDEX_DIRTY_ROOT);
|
|
_treeView.addCanNotDragOutList(INDEX_PROJECT);
|
|
|
|
_treeView.display();
|
|
if (!openWorkSpace(_workSpaceFilePath.c_str()))
|
|
newWorkSpace();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
if (_treeView.isDragging())
|
|
_treeView.dragItem(_hSelf, LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
if (_treeView.isDragging())
|
|
if (_treeView.dropItem())
|
|
setWorkSpaceDirty(true);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
notified((LPNMHDR)lParam);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_SIZE:
|
|
{
|
|
int width = LOWORD(lParam);
|
|
int height = HIWORD(lParam);
|
|
RECT toolbarMenuRect;
|
|
::GetClientRect(_hToolbarMenu, &toolbarMenuRect);
|
|
|
|
::MoveWindow(_hToolbarMenu, 0, 0, width, toolbarMenuRect.bottom, TRUE);
|
|
|
|
HWND hwnd = _treeView.getHSelf();
|
|
if (hwnd)
|
|
::MoveWindow(hwnd, 0, toolbarMenuRect.bottom + 2, width, height - toolbarMenuRect.bottom - 2, TRUE);
|
|
break;
|
|
}
|
|
|
|
case WM_CONTEXTMENU:
|
|
if (!_treeView.isDragging())
|
|
showContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
popupMenuCmd(LOWORD(wParam));
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
_treeView.destroy();
|
|
destroyMenus();
|
|
::DestroyWindow(_hToolbarMenu);
|
|
break;
|
|
}
|
|
case WM_KEYDOWN:
|
|
//if (wParam == VK_F2)
|
|
{
|
|
::MessageBoxA(NULL,"vkF2","",MB_OK);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
|
|
}
|
|
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
|
|
}
|
|
|
|
void ProjectPanel::checkIfNeedSave(const TCHAR *title)
|
|
{
|
|
if (_isDirty)
|
|
{
|
|
display();
|
|
int res = ::MessageBox(_hSelf, TEXT("The workspace was modified. Do you want to save it?"), title, MB_YESNO | MB_ICONQUESTION);
|
|
if (res == IDYES)
|
|
{
|
|
if (!saveWorkSpace())
|
|
::MessageBox(_hSelf, TEXT("Your workspace was not saved."), title, MB_OK | MB_ICONERROR);
|
|
}
|
|
//else if (res == IDNO)
|
|
// Don't save so do nothing here
|
|
}
|
|
}
|
|
|
|
void ProjectPanel::initMenus()
|
|
{
|
|
_hWorkSpaceMenu = ::CreatePopupMenu();
|
|
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
|
|
generic_string new_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_NEWWS, PM_NEWWORKSPACE);
|
|
generic_string open_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_OPENWS, PM_OPENWORKSPACE);
|
|
generic_string reload_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_RELOADWS, PM_RELOADWORKSPACE);
|
|
generic_string save_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_SAVEWS, PM_SAVEWORKSPACE);
|
|
generic_string saveas_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_SAVEASWS, PM_SAVEASWORKSPACE);
|
|
generic_string saveacopyas_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_SAVEACOPYASWS, PM_SAVEACOPYASWORKSPACE);
|
|
generic_string newproject_workspace = pNativeSpeaker->getProjectPanelLangMenuStr("WorkspaceMenu", IDM_PROJECT_NEWPROJECT, PM_NEWPROJECTWORKSPACE);
|
|
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_NEWWS, new_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_OPENWS, open_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_RELOADWS, reload_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_SAVEWS, save_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_SAVEASWS, saveas_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_SAVEACOPYASWS, saveacopyas_workspace.c_str());
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, (UINT)-1, 0);
|
|
::InsertMenu(_hWorkSpaceMenu, 0, MF_BYCOMMAND, IDM_PROJECT_NEWPROJECT, newproject_workspace.c_str());
|
|
|
|
generic_string edit_moveup = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_MOVEUP, PM_MOVEUPENTRY);
|
|
generic_string edit_movedown = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_MOVEDOWN, PM_MOVEDOWNENTRY);
|
|
generic_string edit_rename = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_RENAME, PM_EDITRENAME);
|
|
generic_string edit_addfolder = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_NEWFOLDER, PM_EDITNEWFOLDER);
|
|
generic_string edit_addfiles = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_ADDFILES, PM_EDITADDFILES);
|
|
generic_string edit_addfilesRecursive = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_ADDFILESRECUSIVELY, PM_EDITADDFILESRECUSIVELY);
|
|
generic_string edit_remove = pNativeSpeaker->getProjectPanelLangMenuStr("ProjectMenu", IDM_PROJECT_DELETEFOLDER, PM_EDITREMOVE);
|
|
|
|
_hProjectMenu = ::CreatePopupMenu();
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEUP, edit_moveup.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEDOWN, edit_movedown.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, UINT(-1), 0);
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_RENAME, edit_rename.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_NEWFOLDER, edit_addfolder.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_ADDFILES, edit_addfiles.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_ADDFILESRECUSIVELY, edit_addfilesRecursive.c_str());
|
|
::InsertMenu(_hProjectMenu, 0, MF_BYCOMMAND, IDM_PROJECT_DELETEFOLDER, edit_remove.c_str());
|
|
|
|
edit_moveup = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_MOVEUP, PM_MOVEUPENTRY);
|
|
edit_movedown = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_MOVEDOWN, PM_MOVEDOWNENTRY);
|
|
edit_rename = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_RENAME, PM_EDITRENAME);
|
|
edit_addfolder = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_NEWFOLDER, PM_EDITNEWFOLDER);
|
|
edit_addfiles = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_ADDFILES, PM_EDITADDFILES);
|
|
edit_addfilesRecursive = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_ADDFILESRECUSIVELY, PM_EDITADDFILESRECUSIVELY);
|
|
edit_remove = pNativeSpeaker->getProjectPanelLangMenuStr("FolderMenu", IDM_PROJECT_DELETEFOLDER, PM_EDITREMOVE);
|
|
|
|
_hFolderMenu = ::CreatePopupMenu();
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEUP, edit_moveup.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEDOWN, edit_movedown.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, UINT(-1), 0);
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_RENAME, edit_rename.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_NEWFOLDER, edit_addfolder.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_ADDFILES, edit_addfiles.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_ADDFILESRECUSIVELY, edit_addfilesRecursive.c_str());
|
|
::InsertMenu(_hFolderMenu, 0, MF_BYCOMMAND, IDM_PROJECT_DELETEFOLDER, edit_remove.c_str());
|
|
|
|
edit_moveup = pNativeSpeaker->getProjectPanelLangMenuStr("FileMenu", IDM_PROJECT_MOVEUP, PM_MOVEUPENTRY);
|
|
edit_movedown = pNativeSpeaker->getProjectPanelLangMenuStr("FileMenu", IDM_PROJECT_MOVEDOWN, PM_MOVEDOWNENTRY);
|
|
edit_rename = pNativeSpeaker->getProjectPanelLangMenuStr("FileMenu", IDM_PROJECT_RENAME, PM_EDITRENAME);
|
|
edit_remove = pNativeSpeaker->getProjectPanelLangMenuStr("FileMenu", IDM_PROJECT_DELETEFILE, PM_EDITREMOVE);
|
|
generic_string edit_modifyfile = pNativeSpeaker->getProjectPanelLangMenuStr("FileMenu", IDM_PROJECT_MODIFYFILEPATH, PM_EDITMODIFYFILE);
|
|
|
|
_hFileMenu = ::CreatePopupMenu();
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEUP, edit_moveup.c_str());
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MOVEDOWN, edit_movedown.c_str());
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, UINT(-1), 0);
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_PROJECT_RENAME, edit_rename.c_str());
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_PROJECT_DELETEFILE, edit_remove.c_str());
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_PROJECT_MODIFYFILEPATH, edit_modifyfile.c_str());
|
|
}
|
|
|
|
|
|
BOOL ProjectPanel::setImageList(int root_clean_id, int root_dirty_id, int project_id, int open_node_id, int closed_node_id, int leaf_id, int ivalid_leaf_id)
|
|
{
|
|
HBITMAP hbmp;
|
|
COLORREF maskColour = RGB(192, 192, 192);
|
|
const int nbBitmaps = 7;
|
|
|
|
// Creation of image list
|
|
if ((_hImaLst = ImageList_Create(CX_BITMAP, CY_BITMAP, ILC_COLOR32 | ILC_MASK, nbBitmaps, 0)) == NULL)
|
|
return FALSE;
|
|
|
|
// Add the bmp in the list
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(root_clean_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(root_dirty_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(project_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(open_node_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(closed_node_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(leaf_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(ivalid_leaf_id));
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
ImageList_AddMasked(_hImaLst, hbmp, maskColour);
|
|
DeleteObject(hbmp);
|
|
|
|
if (ImageList_GetImageCount(_hImaLst) < nbBitmaps)
|
|
return FALSE;
|
|
|
|
// Set image list to the tree view
|
|
TreeView_SetImageList(_treeView.getHSelf(), _hImaLst, TVSIL_NORMAL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void ProjectPanel::destroyMenus()
|
|
{
|
|
::DestroyMenu(_hWorkSpaceMenu);
|
|
::DestroyMenu(_hProjectMenu);
|
|
::DestroyMenu(_hFolderMenu);
|
|
::DestroyMenu(_hFileMenu);
|
|
}
|
|
|
|
bool ProjectPanel::openWorkSpace(const TCHAR *projectFileName)
|
|
{
|
|
TiXmlDocument *pXmlDocProject = new TiXmlDocument(projectFileName);
|
|
bool loadOkay = pXmlDocProject->LoadFile();
|
|
if (!loadOkay)
|
|
return false;
|
|
|
|
TiXmlNode *root = pXmlDocProject->FirstChild(TEXT("NotepadPlus"));
|
|
if (!root)
|
|
return false;
|
|
|
|
|
|
TiXmlNode *childNode = root->FirstChildElement(TEXT("Project"));
|
|
if (!childNode)
|
|
return false;
|
|
|
|
if (!::PathFileExists(projectFileName))
|
|
return false;
|
|
|
|
_treeView.removeAllItems();
|
|
_workSpaceFilePath = projectFileName;
|
|
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
generic_string workspace = pNativeSpeaker->getAttrNameStr(PM_WORKSPACEROOTNAME, "ProjectManager", "WorkspaceRootName");
|
|
HTREEITEM rootItem = _treeView.addItem(workspace.c_str(), TVI_ROOT, INDEX_CLEAN_ROOT);
|
|
|
|
for ( ; childNode ; childNode = childNode->NextSibling(TEXT("Project")))
|
|
{
|
|
HTREEITEM projectItem = _treeView.addItem((childNode->ToElement())->Attribute(TEXT("name")), rootItem, INDEX_PROJECT);
|
|
buildTreeFrom(childNode, projectItem);
|
|
}
|
|
setWorkSpaceDirty(false);
|
|
_treeView.expand(rootItem);
|
|
|
|
delete pXmlDocProject;
|
|
return loadOkay;
|
|
}
|
|
|
|
void ProjectPanel::newWorkSpace()
|
|
{
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
generic_string workspace = pNativeSpeaker->getAttrNameStr(PM_WORKSPACEROOTNAME, "ProjectManager", "WorkspaceRootName");
|
|
_treeView.addItem(workspace.c_str(), TVI_ROOT, INDEX_CLEAN_ROOT);
|
|
setWorkSpaceDirty(false);
|
|
_workSpaceFilePath = TEXT("");
|
|
}
|
|
|
|
bool ProjectPanel::saveWorkSpace()
|
|
{
|
|
if (_workSpaceFilePath == TEXT(""))
|
|
{
|
|
return saveWorkSpaceAs(false);
|
|
}
|
|
else
|
|
{
|
|
writeWorkSpace();
|
|
setWorkSpaceDirty(false);
|
|
_isDirty = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool ProjectPanel::writeWorkSpace(TCHAR *projectFileName)
|
|
{
|
|
//write <NotepadPlus>: use the default file name if new file name is not given
|
|
const TCHAR * fn2write = projectFileName?projectFileName:_workSpaceFilePath.c_str();
|
|
TiXmlDocument projDoc(fn2write);
|
|
TiXmlNode *root = projDoc.InsertEndChild(TiXmlElement(TEXT("NotepadPlus")));
|
|
|
|
TCHAR textBuffer[MAX_PATH];
|
|
TVITEM tvItem;
|
|
tvItem.mask = TVIF_TEXT;
|
|
tvItem.pszText = textBuffer;
|
|
tvItem.cchTextMax = MAX_PATH;
|
|
|
|
//for each project, write <Project>
|
|
HTREEITEM tvRoot = _treeView.getRoot();
|
|
if (!tvRoot)
|
|
return false;
|
|
|
|
for (HTREEITEM tvProj = _treeView.getChildFrom(tvRoot);
|
|
tvProj != NULL;
|
|
tvProj = _treeView.getNextSibling(tvProj))
|
|
{
|
|
tvItem.hItem = tvProj;
|
|
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
//printStr(tvItem.pszText);
|
|
|
|
TiXmlNode *projRoot = root->InsertEndChild(TiXmlElement(TEXT("Project")));
|
|
projRoot->ToElement()->SetAttribute(TEXT("name"), tvItem.pszText);
|
|
buildProjectXml(projRoot, tvProj, fn2write);
|
|
}
|
|
projDoc.SaveFile();
|
|
return true;
|
|
}
|
|
|
|
void ProjectPanel::buildProjectXml(TiXmlNode *node, HTREEITEM hItem, const TCHAR* fn2write)
|
|
{
|
|
TCHAR textBuffer[MAX_PATH];
|
|
TVITEM tvItem;
|
|
tvItem.mask = TVIF_TEXT | TVIF_PARAM;
|
|
tvItem.pszText = textBuffer;
|
|
tvItem.cchTextMax = MAX_PATH;
|
|
|
|
for (HTREEITEM hItemNode = _treeView.getChildFrom(hItem);
|
|
hItemNode != NULL;
|
|
hItemNode = _treeView.getNextSibling(hItemNode))
|
|
{
|
|
tvItem.hItem = hItemNode;
|
|
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
if (tvItem.lParam != NULL)
|
|
{
|
|
generic_string *fn = (generic_string *)tvItem.lParam;
|
|
generic_string newFn = getRelativePath(*fn, fn2write);
|
|
TiXmlNode *fileLeaf = node->InsertEndChild(TiXmlElement(TEXT("File")));
|
|
fileLeaf->ToElement()->SetAttribute(TEXT("name"), newFn.c_str());
|
|
}
|
|
else
|
|
{
|
|
TiXmlNode *folderNode = node->InsertEndChild(TiXmlElement(TEXT("Folder")));
|
|
folderNode->ToElement()->SetAttribute(TEXT("name"), tvItem.pszText);
|
|
buildProjectXml(folderNode, hItemNode, fn2write);
|
|
}
|
|
}
|
|
}
|
|
|
|
generic_string ProjectPanel::getRelativePath(const generic_string & filePath, const TCHAR *workSpaceFileName)
|
|
{
|
|
TCHAR wsfn[MAX_PATH];
|
|
lstrcpy(wsfn, workSpaceFileName);
|
|
::PathRemoveFileSpec(wsfn);
|
|
|
|
size_t pos_found = filePath.find(wsfn);
|
|
if (pos_found == generic_string::npos)
|
|
return filePath;
|
|
const TCHAR *relativeFile = filePath.c_str() + lstrlen(wsfn);
|
|
if (relativeFile[0] == '\\')
|
|
++relativeFile;
|
|
return relativeFile;
|
|
}
|
|
|
|
bool ProjectPanel::buildTreeFrom(TiXmlNode *projectRoot, HTREEITEM hParentItem)
|
|
{
|
|
for (TiXmlNode *childNode = projectRoot->FirstChildElement();
|
|
childNode ;
|
|
childNode = childNode->NextSibling())
|
|
{
|
|
const TCHAR *v = childNode->Value();
|
|
if (lstrcmp(TEXT("Folder"), v) == 0)
|
|
{
|
|
HTREEITEM addedItem = _treeView.addItem((childNode->ToElement())->Attribute(TEXT("name")), hParentItem, INDEX_CLOSED_NODE);
|
|
if (!childNode->NoChildren())
|
|
{
|
|
bool isOK = buildTreeFrom(childNode, addedItem);
|
|
if (!isOK)
|
|
return false;
|
|
}
|
|
}
|
|
else if (lstrcmp(TEXT("File"), v) == 0)
|
|
{
|
|
const TCHAR *strValue = (childNode->ToElement())->Attribute(TEXT("name"));
|
|
generic_string fullPath = getAbsoluteFilePath(strValue);
|
|
TCHAR *strValueLabel = ::PathFindFileName(strValue);
|
|
int iImage = ::PathFileExists(fullPath.c_str())?INDEX_LEAF:INDEX_LEAF_INVALID;
|
|
_treeView.addItem(strValueLabel, hParentItem, iImage, fullPath.c_str());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
generic_string ProjectPanel::getAbsoluteFilePath(const TCHAR * relativePath)
|
|
{
|
|
if (!::PathIsRelative(relativePath))
|
|
return relativePath;
|
|
|
|
TCHAR absolutePath[MAX_PATH];
|
|
lstrcpy(absolutePath, _workSpaceFilePath.c_str());
|
|
::PathRemoveFileSpec(absolutePath);
|
|
::PathAppend(absolutePath, relativePath);
|
|
return absolutePath;
|
|
}
|
|
|
|
void ProjectPanel::openSelectFile()
|
|
{
|
|
TVITEM tvItem;
|
|
tvItem.mask = TVIF_PARAM;
|
|
tvItem.hItem = _treeView.getSelection();
|
|
::SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
|
|
NodeType nType = getNodeType(tvItem.hItem);
|
|
generic_string *fn = (generic_string *)tvItem.lParam;
|
|
if (nType == nodeType_file && fn)
|
|
{
|
|
tvItem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
if (::PathFileExists(fn->c_str()))
|
|
{
|
|
::SendMessage(_hParent, NPPM_DOOPEN, 0, (LPARAM)(fn->c_str()));
|
|
tvItem.iImage = INDEX_LEAF;
|
|
tvItem.iSelectedImage = INDEX_LEAF;
|
|
}
|
|
else
|
|
{
|
|
tvItem.iImage = INDEX_LEAF_INVALID;
|
|
tvItem.iSelectedImage = INDEX_LEAF_INVALID;
|
|
}
|
|
TreeView_SetItem(_treeView.getHSelf(), &tvItem);
|
|
}
|
|
}
|
|
|
|
|
|
void ProjectPanel::notified(LPNMHDR notification)
|
|
{
|
|
if ((notification->hwndFrom == _treeView.getHSelf()))
|
|
{
|
|
TCHAR textBuffer[MAX_PATH];
|
|
TVITEM tvItem;
|
|
tvItem.mask = TVIF_TEXT | TVIF_PARAM;
|
|
tvItem.pszText = textBuffer;
|
|
tvItem.cchTextMax = MAX_PATH;
|
|
|
|
switch (notification->code)
|
|
{
|
|
case NM_DBLCLK:
|
|
{
|
|
openSelectFile();
|
|
}
|
|
break;
|
|
|
|
case TVN_ENDLABELEDIT:
|
|
{
|
|
LPNMTVDISPINFO tvnotif = (LPNMTVDISPINFO)notification;
|
|
if (!tvnotif->item.pszText)
|
|
return;
|
|
if (getNodeType(tvnotif->item.hItem) == nodeType_root)
|
|
return;
|
|
|
|
// Processing for only File case
|
|
if (tvnotif->item.lParam)
|
|
{
|
|
// Get the old label
|
|
tvItem.hItem = _treeView.getSelection();
|
|
::SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
size_t len = lstrlen(tvItem.pszText);
|
|
|
|
// Find the position of old label in File path
|
|
generic_string *filePath = (generic_string *)tvnotif->item.lParam;
|
|
size_t found = filePath->rfind(tvItem.pszText);
|
|
|
|
// If found the old label, replace it with the modified one
|
|
if (found != generic_string::npos)
|
|
filePath->replace(found, len, tvnotif->item.pszText);
|
|
|
|
// Check the validity of modified file path
|
|
tvItem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
if (::PathFileExists(filePath->c_str()))
|
|
{
|
|
tvItem.iImage = INDEX_LEAF;
|
|
tvItem.iSelectedImage = INDEX_LEAF;
|
|
}
|
|
else
|
|
{
|
|
tvItem.iImage = INDEX_LEAF_INVALID;
|
|
tvItem.iSelectedImage = INDEX_LEAF_INVALID;
|
|
}
|
|
TreeView_SetItem(_treeView.getHSelf(), &tvItem);
|
|
}
|
|
|
|
// For File, Folder and Project
|
|
::SendMessage(_treeView.getHSelf(), TVM_SETITEM, 0,(LPARAM)(&(tvnotif->item)));
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
break;
|
|
|
|
case TVN_GETINFOTIP:
|
|
{
|
|
LPNMTVGETINFOTIP lpGetInfoTip = (LPNMTVGETINFOTIP)notification;
|
|
generic_string *str = NULL ;
|
|
|
|
if (_treeView.getRoot() == lpGetInfoTip->hItem)
|
|
{
|
|
str = &_workSpaceFilePath;
|
|
}
|
|
else
|
|
{
|
|
str = (generic_string *)lpGetInfoTip->lParam;
|
|
if (!str)
|
|
return;
|
|
}
|
|
lpGetInfoTip->pszText = (LPTSTR)str->c_str();
|
|
lpGetInfoTip->cchTextMax = str->size();
|
|
}
|
|
break;
|
|
|
|
case TVN_KEYDOWN:
|
|
{
|
|
//tvItem.hItem = _treeView.getSelection();
|
|
//::SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
LPNMTVKEYDOWN ptvkd = (LPNMTVKEYDOWN)notification;
|
|
|
|
if (ptvkd->wVKey == VK_DELETE)
|
|
{
|
|
HTREEITEM hItem = _treeView.getSelection();
|
|
NodeType nType = getNodeType(hItem);
|
|
if (nType == nodeType_project || nType == nodeType_folder)
|
|
popupMenuCmd(IDM_PROJECT_DELETEFOLDER);
|
|
else if (nType == nodeType_file)
|
|
popupMenuCmd(IDM_PROJECT_DELETEFILE);
|
|
}
|
|
else if (ptvkd->wVKey == VK_RETURN)
|
|
{
|
|
HTREEITEM hItem = _treeView.getSelection();
|
|
NodeType nType = getNodeType(hItem);
|
|
if (nType == nodeType_file)
|
|
openSelectFile();
|
|
else
|
|
_treeView.toggleExpandCollapse(hItem);
|
|
}
|
|
else if (ptvkd->wVKey == VK_UP)
|
|
{
|
|
if (0x80 & GetKeyState(VK_CONTROL))
|
|
{
|
|
popupMenuCmd(IDM_PROJECT_MOVEUP);
|
|
}
|
|
}
|
|
else if (ptvkd->wVKey == VK_DOWN)
|
|
{
|
|
if (0x80 & GetKeyState(VK_CONTROL))
|
|
{
|
|
popupMenuCmd(IDM_PROJECT_MOVEDOWN);
|
|
}
|
|
}
|
|
else if (ptvkd->wVKey == VK_F2)
|
|
popupMenuCmd(IDM_PROJECT_RENAME);
|
|
|
|
}
|
|
break;
|
|
|
|
case TVN_ITEMEXPANDED:
|
|
{
|
|
LPNMTREEVIEW nmtv = (LPNMTREEVIEW)notification;
|
|
tvItem.hItem = nmtv->itemNew.hItem;
|
|
tvItem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
|
|
if (getNodeType(nmtv->itemNew.hItem) == nodeType_folder)
|
|
{
|
|
if (nmtv->action == TVE_COLLAPSE)
|
|
{
|
|
_treeView.setItemImage(nmtv->itemNew.hItem, INDEX_CLOSED_NODE, INDEX_CLOSED_NODE);
|
|
}
|
|
else if (nmtv->action == TVE_EXPAND)
|
|
{
|
|
_treeView.setItemImage(nmtv->itemNew.hItem, INDEX_OPEN_NODE, INDEX_OPEN_NODE);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TVN_BEGINDRAG:
|
|
{
|
|
//printStr(TEXT("hello"));
|
|
_treeView.beginDrag((LPNMTREEVIEW)notification);
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProjectPanel::setWorkSpaceDirty(bool isDirty)
|
|
{
|
|
_isDirty = isDirty;
|
|
int iImg = _isDirty?INDEX_DIRTY_ROOT:INDEX_CLEAN_ROOT;
|
|
_treeView.setItemImage(_treeView.getRoot(), iImg, iImg);
|
|
}
|
|
|
|
NodeType ProjectPanel::getNodeType(HTREEITEM hItem)
|
|
{
|
|
TVITEM tvItem;
|
|
tvItem.hItem = hItem;
|
|
tvItem.mask = TVIF_IMAGE | TVIF_PARAM;
|
|
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
|
|
// Root
|
|
if (tvItem.iImage == INDEX_CLEAN_ROOT || tvItem.iImage == INDEX_DIRTY_ROOT)
|
|
{
|
|
return nodeType_root;
|
|
}
|
|
// Project
|
|
else if (tvItem.iImage == INDEX_PROJECT)
|
|
{
|
|
return nodeType_project;
|
|
}
|
|
// Folder
|
|
else if (tvItem.lParam == NULL)
|
|
{
|
|
return nodeType_folder;
|
|
}
|
|
// File
|
|
else
|
|
{
|
|
return nodeType_file;
|
|
}
|
|
}
|
|
|
|
void ProjectPanel::showContextMenu(int x, int y)
|
|
{
|
|
TVHITTESTINFO tvHitInfo;
|
|
HTREEITEM hTreeItem;
|
|
|
|
// Detect if the given position is on the element TVITEM
|
|
tvHitInfo.pt.x = x;
|
|
tvHitInfo.pt.y = y;
|
|
tvHitInfo.flags = 0;
|
|
ScreenToClient(_treeView.getHSelf(), &(tvHitInfo.pt));
|
|
hTreeItem = TreeView_HitTest(_treeView.getHSelf(), &tvHitInfo);
|
|
|
|
if (tvHitInfo.hItem != NULL)
|
|
{
|
|
// Make item selected
|
|
_treeView.selectItem(tvHitInfo.hItem);
|
|
|
|
// get clicked item type
|
|
NodeType nodeType = getNodeType(tvHitInfo.hItem);
|
|
HMENU hMenu = NULL;
|
|
if (nodeType == nodeType_root)
|
|
hMenu = _hWorkSpaceMenu;
|
|
else if (nodeType == nodeType_project)
|
|
hMenu = _hProjectMenu;
|
|
else if (nodeType == nodeType_folder)
|
|
hMenu = _hFolderMenu;
|
|
else //nodeType_file
|
|
hMenu = _hFileMenu;
|
|
TrackPopupMenu(hMenu, TPM_LEFTALIGN, x, y, 0, _hSelf, NULL);
|
|
}
|
|
}
|
|
|
|
POINT ProjectPanel::getMenuDisplayPoint(int iButton)
|
|
{
|
|
POINT p;
|
|
RECT btnRect;
|
|
SendMessage(_hToolbarMenu, TB_GETITEMRECT, iButton, (LPARAM)&btnRect);
|
|
|
|
p.x = btnRect.left;
|
|
p.y = btnRect.top + btnRect.bottom;
|
|
ClientToScreen(_hToolbarMenu, &p);
|
|
return p;
|
|
}
|
|
|
|
HTREEITEM ProjectPanel::addFolder(HTREEITEM hTreeItem, const TCHAR *folderName)
|
|
{
|
|
HTREEITEM addedItem = _treeView.addItem(folderName, hTreeItem, INDEX_CLOSED_NODE);
|
|
|
|
TreeView_Expand(_treeView.getHSelf(), hTreeItem, TVE_EXPAND);
|
|
TreeView_EditLabel(_treeView.getHSelf(), addedItem);
|
|
if (getNodeType(hTreeItem) == nodeType_folder)
|
|
_treeView.setItemImage(hTreeItem, INDEX_OPEN_NODE, INDEX_OPEN_NODE);
|
|
|
|
return addedItem;
|
|
}
|
|
|
|
void ProjectPanel::popupMenuCmd(int cmdID)
|
|
{
|
|
// get selected item handle
|
|
HTREEITEM hTreeItem = _treeView.getSelection();
|
|
if (!hTreeItem)
|
|
return;
|
|
|
|
switch (cmdID)
|
|
{
|
|
//
|
|
// Toolbar menu buttons
|
|
//
|
|
case IDB_PROJECT_BTN:
|
|
{
|
|
POINT p = getMenuDisplayPoint(0);
|
|
TrackPopupMenu(_hWorkSpaceMenu, TPM_LEFTALIGN, p.x, p.y, 0, _hSelf, NULL);
|
|
}
|
|
break;
|
|
|
|
case IDB_EDIT_BTN:
|
|
{
|
|
POINT p = getMenuDisplayPoint(1);
|
|
HMENU hMenu = NULL;
|
|
NodeType nodeType = getNodeType(hTreeItem);
|
|
if (nodeType == nodeType_project)
|
|
hMenu = _hProjectMenu;
|
|
else if (nodeType == nodeType_folder)
|
|
hMenu = _hFolderMenu;
|
|
else if (nodeType == nodeType_file)
|
|
hMenu = _hFileMenu;
|
|
if (hMenu)
|
|
TrackPopupMenu(hMenu, TPM_LEFTALIGN, p.x, p.y, 0, _hSelf, NULL);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Toolbar menu commands
|
|
//
|
|
case IDM_PROJECT_NEWPROJECT :
|
|
{
|
|
HTREEITEM root = _treeView.getRoot();
|
|
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
generic_string newProjectLabel = pNativeSpeaker->getAttrNameStr(PM_NEWPROJECTNAME, "ProjectManager", "NewProjectName");
|
|
HTREEITEM addedItem = _treeView.addItem(newProjectLabel.c_str(), root, INDEX_PROJECT);
|
|
setWorkSpaceDirty(true);
|
|
_treeView.expand(hTreeItem);
|
|
TreeView_EditLabel(_treeView.getHSelf(), addedItem);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_NEWWS :
|
|
{
|
|
if (_isDirty)
|
|
{
|
|
int res = ::MessageBox(_hSelf, TEXT("The current workspace was modified. Do you want to save the current project?"), TEXT("New Workspace"), MB_YESNOCANCEL | MB_ICONQUESTION | MB_APPLMODAL);
|
|
if (res == IDYES)
|
|
{
|
|
if (!saveWorkSpace())
|
|
return;
|
|
}
|
|
else if (res == IDNO)
|
|
{
|
|
// Don't save so do nothing here
|
|
}
|
|
else if (res == IDCANCEL)
|
|
{
|
|
// User cancels action "New Workspace" so we interrupt here
|
|
return;
|
|
}
|
|
}
|
|
_treeView.removeAllItems();
|
|
newWorkSpace();
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_RENAME :
|
|
TreeView_EditLabel(_treeView.getHSelf(), hTreeItem);
|
|
break;
|
|
|
|
case IDM_PROJECT_NEWFOLDER :
|
|
{
|
|
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
|
|
generic_string newFolderLabel = pNativeSpeaker->getAttrNameStr(PM_NEWFOLDERNAME, "ProjectManager", "NewFolderName");
|
|
addFolder(hTreeItem, newFolderLabel.c_str());
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_MOVEDOWN :
|
|
{
|
|
if (_treeView.moveDown(hTreeItem))
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_MOVEUP :
|
|
{
|
|
if (_treeView.moveUp(hTreeItem))
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_ADDFILES :
|
|
{
|
|
addFiles(hTreeItem);
|
|
if (getNodeType(hTreeItem) == nodeType_folder)
|
|
_treeView.setItemImage(hTreeItem, INDEX_OPEN_NODE, INDEX_OPEN_NODE);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_ADDFILESRECUSIVELY :
|
|
{
|
|
addFilesFromDirectory(hTreeItem);
|
|
if (getNodeType(hTreeItem) == nodeType_folder)
|
|
_treeView.setItemImage(hTreeItem, INDEX_OPEN_NODE, INDEX_OPEN_NODE);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_OPENWS:
|
|
{
|
|
if (_isDirty)
|
|
{
|
|
int res = ::MessageBox(_hSelf, TEXT("The current workspace was modified. Do you want to save the current project?"), TEXT("Open Workspace"), MB_YESNOCANCEL | MB_ICONQUESTION | MB_APPLMODAL);
|
|
if (res == IDYES)
|
|
{
|
|
if (!saveWorkSpace())
|
|
return;
|
|
}
|
|
else if (res == IDNO)
|
|
{
|
|
// Don't save so do nothing here
|
|
}
|
|
else if (res == IDCANCEL)
|
|
{
|
|
// User cancels action "New Workspace" so we interrupt here
|
|
return;
|
|
}
|
|
}
|
|
|
|
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
|
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
|
if (TCHAR *fn = fDlg.doOpenSingleFileDlg())
|
|
{
|
|
if (!openWorkSpace(fn))
|
|
{
|
|
::MessageBox(_hSelf, TEXT("The workspace could not be opened.\rIt seems the file to open is not a valid project file."), TEXT("Open Workspace"), MB_OK);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_RELOADWS:
|
|
{
|
|
if (_isDirty)
|
|
{
|
|
int res = ::MessageBox(_hSelf, TEXT("The current workspace was modified. Reloading will discard all modifications.\rDo you want to continue?"), TEXT("Reload Workspace"), MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL);
|
|
if (res == IDYES)
|
|
{
|
|
// Do nothing
|
|
}
|
|
else if (res == IDNO)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (::PathFileExists(_workSpaceFilePath.c_str()))
|
|
{
|
|
openWorkSpace(_workSpaceFilePath.c_str());
|
|
}
|
|
else
|
|
{
|
|
::MessageBox(_hSelf, TEXT("Cannot find the file to reload."), TEXT("Reload Workspace"), MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_SAVEWS:
|
|
saveWorkSpace();
|
|
break;
|
|
|
|
case IDM_PROJECT_SAVEACOPYASWS:
|
|
case IDM_PROJECT_SAVEASWS:
|
|
{
|
|
saveWorkSpaceAs(cmdID == IDM_PROJECT_SAVEACOPYASWS);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_DELETEFOLDER :
|
|
{
|
|
HTREEITEM parent = _treeView.getParent(hTreeItem);
|
|
|
|
if (_treeView.getChildFrom(hTreeItem) != NULL)
|
|
{
|
|
TCHAR str2display[MAX_PATH] = TEXT("All the sub-items will be removed.\rAre you sure you want to remove this folder from the project?");
|
|
if (::MessageBox(_hSelf, str2display, TEXT("Remove folder from project"), MB_YESNO) == IDYES)
|
|
{
|
|
_treeView.removeItem(hTreeItem);
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_treeView.removeItem(hTreeItem);
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
if (getNodeType(parent) == nodeType_folder)
|
|
_treeView.setItemImage(parent, INDEX_CLOSED_NODE, INDEX_CLOSED_NODE);
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_DELETEFILE :
|
|
{
|
|
HTREEITEM parent = _treeView.getParent(hTreeItem);
|
|
|
|
TCHAR str2display[MAX_PATH] = TEXT("Are you sure you want to remove this file from the project?");
|
|
if (::MessageBox(_hSelf, str2display, TEXT("Remove file from project"), MB_YESNO) == IDYES)
|
|
{
|
|
_treeView.removeItem(hTreeItem);
|
|
setWorkSpaceDirty(true);
|
|
if (getNodeType(parent) == nodeType_folder)
|
|
_treeView.setItemImage(parent, INDEX_CLOSED_NODE, INDEX_CLOSED_NODE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_PROJECT_MODIFYFILEPATH :
|
|
{
|
|
FileRelocalizerDlg fileRelocalizerDlg;
|
|
fileRelocalizerDlg.init(_hInst, _hParent);
|
|
|
|
TCHAR textBuffer[MAX_PATH];
|
|
TVITEM tvItem;
|
|
tvItem.hItem = hTreeItem;
|
|
tvItem.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
tvItem.pszText = textBuffer;
|
|
tvItem.cchTextMax = MAX_PATH;
|
|
|
|
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0,(LPARAM)&tvItem);
|
|
if (!tvItem.lParam)
|
|
return;
|
|
generic_string * fn = (generic_string *)tvItem.lParam;
|
|
|
|
if (fileRelocalizerDlg.doDialog(fn->c_str()) == 0)
|
|
{
|
|
generic_string newValue = fileRelocalizerDlg.getFullFilePath();
|
|
if (*fn == newValue)
|
|
return;
|
|
|
|
*fn = newValue;
|
|
TCHAR *strValueLabel = ::PathFindFileName(fn->c_str());
|
|
lstrcpy(textBuffer, strValueLabel);
|
|
int iImage = ::PathFileExists(fn->c_str())?INDEX_LEAF:INDEX_LEAF_INVALID;
|
|
tvItem.iImage = tvItem.iSelectedImage = iImage;
|
|
SendMessage(_treeView.getHSelf(), TVM_SETITEM, 0,(LPARAM)&tvItem);
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool ProjectPanel::saveWorkSpaceAs(bool saveCopyAs)
|
|
{
|
|
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
|
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
|
|
|
if (TCHAR *fn = fDlg.doSaveDlg())
|
|
{
|
|
writeWorkSpace(fn);
|
|
if (!saveCopyAs)
|
|
{
|
|
_workSpaceFilePath = fn;
|
|
setWorkSpaceDirty(false);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ProjectPanel::addFiles(HTREEITEM hTreeItem)
|
|
{
|
|
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
|
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
|
|
|
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
|
{
|
|
size_t sz = pfns->size();
|
|
for (size_t i = 0 ; i < sz ; ++i)
|
|
{
|
|
TCHAR *strValueLabel = ::PathFindFileName(pfns->at(i).c_str());
|
|
_treeView.addItem(strValueLabel, hTreeItem, INDEX_LEAF, pfns->at(i).c_str());
|
|
}
|
|
_treeView.expand(hTreeItem);
|
|
setWorkSpaceDirty(true);
|
|
}
|
|
}
|
|
|
|
void ProjectPanel::recursiveAddFilesFrom(const TCHAR *folderPath, HTREEITEM hTreeItem)
|
|
{
|
|
bool isRecursive = true;
|
|
bool isInHiddenDir = false;
|
|
generic_string dirFilter(folderPath);
|
|
if (folderPath[lstrlen(folderPath)-1] != '\\')
|
|
dirFilter += TEXT("\\");
|
|
|
|
dirFilter += TEXT("*.*");
|
|
WIN32_FIND_DATA foundData;
|
|
std::vector<generic_string> files;
|
|
|
|
HANDLE hFile = ::FindFirstFile(dirFilter.c_str(), &foundData);
|
|
|
|
do {
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
break;
|
|
|
|
if (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (!isInHiddenDir && (foundData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
|
|
{
|
|
// do nothing
|
|
}
|
|
else if (isRecursive)
|
|
{
|
|
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
|
{
|
|
generic_string pathDir(folderPath);
|
|
if (folderPath[lstrlen(folderPath)-1] != '\\')
|
|
pathDir += TEXT("\\");
|
|
pathDir += foundData.cFileName;
|
|
pathDir += TEXT("\\");
|
|
HTREEITEM addedItem = addFolder(hTreeItem, foundData.cFileName);
|
|
recursiveAddFilesFrom(pathDir.c_str(), addedItem);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
files.push_back(foundData.cFileName);
|
|
}
|
|
} while (::FindNextFile(hFile, &foundData));
|
|
|
|
for (size_t i = 0, len = files.size() ; i < len ; ++i)
|
|
{
|
|
generic_string pathFile(folderPath);
|
|
if (folderPath[lstrlen(folderPath)-1] != '\\')
|
|
pathFile += TEXT("\\");
|
|
pathFile += files[i];
|
|
_treeView.addItem(files[i].c_str(), hTreeItem, INDEX_LEAF, pathFile.c_str());
|
|
}
|
|
|
|
::FindClose(hFile);
|
|
}
|
|
|
|
void ProjectPanel::addFilesFromDirectory(HTREEITEM hTreeItem)
|
|
{
|
|
if (_selDirOfFilesFromDirDlg == TEXT("") && _workSpaceFilePath != TEXT(""))
|
|
{
|
|
TCHAR dir[MAX_PATH];
|
|
lstrcpy(dir, _workSpaceFilePath.c_str());
|
|
::PathRemoveFileSpec(dir);
|
|
_selDirOfFilesFromDirDlg = dir;
|
|
}
|
|
generic_string dirPath;
|
|
if (_selDirOfFilesFromDirDlg != TEXT(""))
|
|
dirPath = getFolderName(_hSelf, _selDirOfFilesFromDirDlg.c_str());
|
|
else
|
|
dirPath = getFolderName(_hSelf);
|
|
|
|
if (dirPath != TEXT(""))
|
|
{
|
|
recursiveAddFilesFrom(dirPath.c_str(), hTreeItem);
|
|
_treeView.expand(hTreeItem);
|
|
setWorkSpaceDirty(true);
|
|
_selDirOfFilesFromDirDlg = dirPath;
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK FileRelocalizerDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM)
|
|
{
|
|
switch (Message)
|
|
{
|
|
case WM_INITDIALOG :
|
|
{
|
|
goToCenter();
|
|
::SetDlgItemText(_hSelf, IDC_EDIT_FILEFULLPATHNAME, _fullFilePath.c_str());
|
|
return TRUE;
|
|
}
|
|
case WM_COMMAND :
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case IDOK :
|
|
{
|
|
TCHAR textBuf[MAX_PATH];
|
|
::GetDlgItemText(_hSelf, IDC_EDIT_FILEFULLPATHNAME, textBuf, MAX_PATH);
|
|
_fullFilePath = textBuf;
|
|
::EndDialog(_hSelf, 0);
|
|
}
|
|
return TRUE;
|
|
|
|
case IDCANCEL :
|
|
::EndDialog(_hSelf, -1);
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
default :
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
int FileRelocalizerDlg::doDialog(const TCHAR *fn, bool isRTL)
|
|
{
|
|
_fullFilePath = fn;
|
|
|
|
if (isRTL)
|
|
{
|
|
DLGTEMPLATE *pMyDlgTemplate = NULL;
|
|
HGLOBAL hMyDlgTemplate = makeRTLResource(IDD_FILERELOCALIZER_DIALOG, &pMyDlgTemplate);
|
|
int result = ::DialogBoxIndirectParam(_hInst, pMyDlgTemplate, _hParent, dlgProc, (LPARAM)this);
|
|
::GlobalFree(hMyDlgTemplate);
|
|
return result;
|
|
}
|
|
return ::DialogBoxParam(_hInst, MAKEINTRESOURCE(IDD_FILERELOCALIZER_DIALOG), _hParent, dlgProc, (LPARAM)this);
|
|
}
|
|
|