#include "stdafx.h"
#include "ShortcutDlg.h"
#include "PluginInterface.h"
#include "resource.h"
#include "MenuManager.h"
#include "Notepad_plus_msgs.h"
ShortcutDlg::ShortcutDlg(HINSTANCE hInst, NppData& nppData, const TCHAR *scriptDirAppend)
: m_hTree(NULL),
m_hListMenuItems(NULL),
m_hListToolbarItems(NULL),
m_hComboInitialisation(NULL),
m_hImageList(NULL),
m_hDefaultImageIndex(0),
m_hIcons(NULL),
m_iconFolderOpen(0),
m_iconFolderClosed(0),
m_iconPython(0),
m_toolbarItemCount(0),
m_menuItemCount(0),
m_toolbarColumnWidth(100),
m_menuItemColumnWidth(100),
m_currentScript(NULL)
{
Window::init(hInst, nppData._nppHandle);
TCHAR temp[MAX_PATH];
::SendMessage(nppData._nppHandle, NPPM_GETPLUGINSCONFIGDIR, MAX_PATH, reinterpret_cast<LPARAM>(temp));
m_userScriptDir = temp;
m_userScriptDir.append(scriptDirAppend);
::SendMessage(nppData._nppHandle, NPPM_GETNPPDIRECTORY, MAX_PATH, reinterpret_cast<LPARAM>(temp));
m_machineScriptDir = temp;
m_machineScriptDir.append(_T("\\plugins"));
m_machineScriptDir.append(scriptDirAppend);
}
void ShortcutDlg::doDialog()
{
if (!isCreated())
{
create(IDD_SCRIPTCONFIG);
}
clearScripts();
if (BST_CHECKED == ::SendMessage(::GetDlgItem(_hSelf, IDC_RADMACHINE), BM_GETCHECK, 0, 0))
{
populateMachineScripts();
}
else
{
populateUserScripts();
}
populateCurrentItems();
nonScriptSelected();
goToCenter();
}
BOOL CALLBACK ShortcutDlg::run_dlgProc(HWND /* hWnd */, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
onInitDialog();
return TRUE;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
saveConfig();
MenuManager::getInstance()->reconfigure();
//lint -fallthrough
case IDCANCEL:
display(false);
return TRUE;
case IDC_RADMACHINE:
populateMachineScripts();
break;
case IDC_RADUSER:
populateUserScripts();
break;
case IDC_MENUADD:
addMenuItem();
break;
case IDC_MENUREMOVE:
removeMenuItem();
break;
case IDC_TOOLBARADD:
addToolbarItem();
break;
case IDC_TOOLBARREMOVE:
removeToolbarItem();
break;
case IDC_TOOLBARSETICON:
toolbarSetIcon();
break;
default:
break;
}
break;
case WM_NOTIFY:
{
LPNMHDR hdr = reinterpret_cast<LPNMHDR>(lParam);
switch(hdr->idFrom)
{
case IDC_FILETREE:
{
switch (hdr->code)
{
case TVN_GETDISPINFO:
{
LPNMTVDISPINFO lptvdi = reinterpret_cast<LPNMTVDISPINFO>(lParam);
int imageIndex;
if (lptvdi->item.mask & (TVIF_IMAGE |TVIF_SELECTEDIMAGE))
{
if (lptvdi->item.state & TVIS_EXPANDED)
{
imageIndex = m_iconFolderOpen;
}
else
{
// a non-NULL lParam means it's a python file (with a full path)
if (lptvdi->item.lParam)
imageIndex = m_iconPython;
else
imageIndex = m_iconFolderClosed;
}
if (lptvdi->item.state & TVIS_SELECTED)
{
lptvdi->item.iSelectedImage = imageIndex;
lptvdi->item.mask = TVIF_SELECTEDIMAGE;
}
else
{
lptvdi->item.iImage = imageIndex;
lptvdi->item.mask = TVIF_IMAGE;
}
}
return TRUE;
} // end case TVN_GETDISPINFO
case TVN_SELCHANGED:
{
LPNMTREEVIEW pnmtv = reinterpret_cast<LPNMTREEVIEW>(lParam);
if (pnmtv->itemNew.lParam)
{
scriptSelected();
m_currentScript = reinterpret_cast<TCHAR*>(pnmtv->itemNew.lParam);
}
else
{
nonScriptSelected();
m_currentScript = NULL;
}
}
break;
default:
// Other notifications we can ignore
break;
} // end switch (hdr->code)
} // end case IDC_FILETREE
break;
default:
// Other windows we can ignore
break;
} // end switch hdr->idFrom
} // end case WM_NOTIFY
break;
default:
// Other messages we can ignore
break;
} // end switch (message)
return FALSE; // ::DefWindowProc(hWnd, message, wParam, lParam);
}
void ShortcutDlg::onInitDialog()
{
// Set the radio button to default to USER SCRIPTS
::SendMessage(GetDlgItem(_hSelf, IDC_RADUSER), BM_SETCHECK, BST_CHECKED, 0);
::SendMessage(GetDlgItem(_hSelf, IDC_RADMACHINE), BM_SETCHECK, BST_UNCHECKED, 0);
m_hTree = ::GetDlgItem(_hSelf, IDC_FILETREE);
m_hListMenuItems = ::GetDlgItem(_hSelf, IDC_MENUITEMLIST);
m_hListToolbarItems = ::GetDlgItem(_hSelf, IDC_TOOLBARITEMLIST2);
m_hComboInitialisation = ::GetDlgItem(_hSelf, IDC_COMBOINITIALISATION);
InitCommonControls();
HICON hIcon; // handle to icon
// Create a masked image list large enough to hold the icons.
m_hIcons = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 3, 0);
// Load the icon resources, and add the icons to the image list.
hIcon = LoadIcon(_hInst, MAKEINTRESOURCE(IDI_FOLDERCLOSED));
m_iconFolderClosed = ImageList_AddIcon(m_hIcons, hIcon);
hIcon = LoadIcon(_hInst, MAKEINTRESOURCE(IDI_FOLDEROPEN));
m_iconFolderOpen = ImageList_AddIcon(m_hIcons, hIcon);
hIcon = LoadIcon(_hInst, MAKEINTRESOURCE(IDI_PYTHON));
m_iconPython = ImageList_AddIcon(m_hIcons, hIcon);
::SendMessage(m_hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, reinterpret_cast<LPARAM>(m_hIcons));
::SendMessage(m_hTree, TVM_SETIMAGELIST, TVSIL_STATE, reinterpret_cast<LPARAM>(m_hIcons));
m_hImageList = ImageList_Create(16, 16, ILC_MASK |ILC_COLOR32, 5, 1);
HBITMAP hPython = static_cast<HBITMAP>(LoadImage(_hInst, MAKEINTRESOURCE(IDB_PYTHON), IMAGE_BITMAP, 0, 0, LR_COLOR | LR_LOADMAP3DCOLORS | LR_DEFAULTSIZE));
m_hDefaultImageIndex = ImageList_Add(m_hImageList, hPython, NULL);
ListView_SetImageList(m_hListToolbarItems, m_hImageList, LVSIL_SMALL);
LVCOLUMN lvCol;
lvCol.cchTextMax = 10;
lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
lvCol.iSubItem = 0;
lvCol.pszText = _T("Script");
lvCol.fmt = LVCFMT_LEFT;
RECT rect;
::GetClientRect(m_hListToolbarItems, &rect);
m_toolbarColumnWidth = (size_t)((rect.right - rect.left) - 18);
lvCol.cx = (int)m_toolbarColumnWidth;
ListView_InsertColumn(m_hListToolbarItems, 0, &lvCol);
::GetClientRect(m_hListToolbarItems, &rect);
m_menuItemColumnWidth = (size_t)(rect.right - rect.left);
lvCol.cx = (int)m_menuItemColumnWidth;
ListView_InsertColumn(m_hListMenuItems, 0, &lvCol);
ListView_SetExtendedListViewStyle(m_hListToolbarItems, LVS_EX_FULLROWSELECT);
ListView_SetExtendedListViewStyle(m_hListMenuItems, LVS_EX_FULLROWSELECT);
ComboBox_AddString(m_hComboInitialisation, _T("LAZY"));
ComboBox_AddString(m_hComboInitialisation, _T("ATSTARTUP"));
}
void ShortcutDlg::clearScripts()
{
TreeView_DeleteAllItems(m_hTree);
m_itemList.erase(m_itemList.begin(), m_itemList.end());
}
void ShortcutDlg::populateUserScripts()
{
clearScripts();
populateScripts(m_userScriptDir);
}
void ShortcutDlg::populateMachineScripts()
{
clearScripts();
populateScripts(m_machineScriptDir);
}
void ShortcutDlg::populateScripts(tstring dir, HTREEITEM parent /* = TVI_ROOT */)
{
WIN32_FIND_DATA findData;
tstring searchPath(dir);
searchPath.append(_T("\\*"));
HANDLE hFound = FindFirstFile(searchPath.c_str(), &findData);
BOOL found = (hFound != INVALID_HANDLE_VALUE) ? TRUE : FALSE;
HTREEITEM lastItem = TVI_ROOT;
while (found)
{
if (FILE_ATTRIBUTE_DIRECTORY == (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& _tcscmp(findData.cFileName, _T("."))
&& _tcscmp(findData.cFileName, _T("..")))
{
searchPath = dir;
searchPath.append(_T("\\"));
searchPath.append(findData.cFileName);
lastItem = addTreeItem(parent, lastItem, NULL, findData.cFileName, true);
populateScripts(searchPath, lastItem);
}
found = FindNextFile(hFound, &findData);
}
FindClose(hFound);
searchPath = dir;
searchPath.append(_T("\\*.py"));
hFound = FindFirstFile(searchPath.c_str(), &findData);
found = (hFound != INVALID_HANDLE_VALUE) ? TRUE : FALSE;
while(found)
{
tstring fullFilename(dir);
fullFilename.append(_T("\\"));
fullFilename.append(findData.cFileName);
size_t length = fullFilename.size() + 1;
std::shared_ptr<TCHAR> item(new TCHAR[length]);
_tcscpy_s(item.get(), length, fullFilename.c_str());
m_itemList.push_back(item);
lastItem = addTreeItem(parent, lastItem, item.get(), findData.cFileName, false);
found = FindNextFile(hFound, &findData);
}
FindClose(hFound);
}
HTREEITEM ShortcutDlg::addTreeItem(HTREEITEM parent, HTREEITEM /* lastItem */, TCHAR *fullPath, TCHAR *text, bool isDirectory)
{
TV_INSERTSTRUCT tvInsert;
tvInsert.hParent = parent;
tvInsert.hInsertAfter = TVI_SORT;
tvInsert.item.mask = TVIF_TEXT | TVIF_PARAM |TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvInsert.item.lParam = reinterpret_cast<LPARAM>(fullPath);
tvInsert.item.pszText = text;
tvInsert.item.iImage = isDirectory ? I_IMAGECALLBACK : m_iconPython;
tvInsert.item.iSelectedImage = isDirectory ? I_IMAGECALLBACK : m_iconPython;
return (HTREEITEM)SendMessage(m_hTree, TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&tvInsert));
}
void ShortcutDlg::scriptSelected()
{
::EnableWindow(GetDlgItem(_hSelf, IDC_MENUADD), TRUE);
::EnableWindow(GetDlgItem(_hSelf, IDC_TOOLBARADD), TRUE);
}
void ShortcutDlg::nonScriptSelected()
{
::EnableWindow(GetDlgItem(_hSelf, IDC_MENUADD), FALSE);
::EnableWindow(GetDlgItem(_hSelf, IDC_TOOLBARADD), FALSE);
}
void ShortcutDlg::addMenuItem()
{
addMenuItem(m_currentScript);
m_menuItems.push_back(m_currentScript);
}
void ShortcutDlg::addMenuItem(const TCHAR *item)
{
LVITEM lvItem;
lvItem.stateMask = LVIS_SELECTED;
lvItem.state = 0;
lvItem.iItem = (int)(m_menuItemCount++);
lvItem.mask = LVIF_TEXT;
lvItem.iSubItem = 0;
lvItem.state = 0;
lvItem.stateMask = 0;
TCHAR path[MAX_PATH];
_tcscpy_s(path, MAX_PATH, item);
::PathCompactPath(NULL, path, m_menuItemColumnWidth);
lvItem.pszText = path;
lvItem.cchTextMax = (int)_tcslen(path);
ListView_InsertItem(m_hListMenuItems, &lvItem);
}
void ShortcutDlg::removeMenuItem()
{
int index = ListView_GetNextItem(m_hListMenuItems, -1, LVIS_SELECTED);
if (index != -1)
{
ListView_DeleteItem(m_hListMenuItems, index);
m_menuItems.erase(m_menuItems.begin() + index);
}
--m_menuItemCount;
}
void ShortcutDlg::addToolbarItem()
{
addToolbarItem(m_currentScript, NULL);
m_toolbarItems.push_back(std::pair<tstring, std::pair<HBITMAP, tstring> >(m_currentScript, std::pair<HBITMAP, tstring>(static_cast<HBITMAP>(NULL), _T(""))));
}
void ShortcutDlg::addToolbarItem(const TCHAR *item, HBITMAP hBitmap)
{
int imageIndex;
if (NULL == hBitmap)
{
imageIndex = m_hDefaultImageIndex;
}
else
{
imageIndex = ImageList_Add(m_hImageList, hBitmap, NULL);
}
LVITEM lvItem;
lvItem.stateMask = LVIS_SELECTED;
lvItem.state = 0;
lvItem.iItem = (int)(m_toolbarItemCount++);
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
lvItem.iSubItem = 0;
lvItem.state = 0;
lvItem.stateMask = 0;
lvItem.iImage = imageIndex;
TCHAR path[MAX_PATH];
_tcscpy_s(path, MAX_PATH, item);
::PathCompactPath(NULL, path, m_toolbarColumnWidth);
lvItem.pszText = path;
lvItem.cchTextMax = (int)_tcslen(path);
ListView_InsertItem(m_hListToolbarItems, &lvItem);
//int itemWidth = ListView_GetStringWidth(m_hListToolbarItems, item);
//if (itemWidth > m_toolbarColumnWidth)
//{
// ListView_SetColumnWidth(m_hListToolbarItems, 0, itemWidth + COLUMN_PADDING));
//}
//::SendMessage(m_hListToolbarItems, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(item));
}
void ShortcutDlg::removeToolbarItem()
{
int index = ListView_GetNextItem(m_hListToolbarItems, -1, LVIS_SELECTED);
if (index != -1)
{
ListView_DeleteItem(m_hListToolbarItems, index);
m_toolbarItems.erase(m_toolbarItems.begin() + index);
}
--m_toolbarItemCount;
}
void ShortcutDlg::populateCurrentItems()
{
ListView_DeleteAllItems(m_hListMenuItems);
ListView_DeleteAllItems(m_hListToolbarItems);
ConfigFile* configFile = ConfigFile::getInstance();
configFile->refresh();
m_menuItemCount = 0;
m_menuItems = configFile->getMenuItems();
for(ConfigFile::MenuItemsTD::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
{
addMenuItem(it->c_str());
}
m_toolbarItemCount = 0;
m_toolbarItems = configFile->getToolbarItems();
for(ConfigFile::ToolbarItemsTD::iterator it = m_toolbarItems.begin(); it != m_toolbarItems.end(); ++it)
{
addToolbarItem(it->first.c_str(), it->second.first);
}
// Try to select the startup type, if it's not there, then just select the first
if (CB_ERR == ComboBox_SelectString(m_hComboInitialisation, 0, configFile->getSetting(_T("STARTUP")).c_str()))
{
ComboBox_SetCurSel(m_hComboInitialisation, 0);
}
}
void ShortcutDlg::saveConfig()
{
ConfigFile* configFile = ConfigFile::getInstance();
configFile->clearItems();
for (ConfigFile::MenuItemsTD::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
{
configFile->addMenuItem(*it);
}
for (ConfigFile::ToolbarItemsTD::iterator it = m_toolbarItems.begin(); it != m_toolbarItems.end(); ++it)
{
configFile->addToolbarItem(it->first, it->second.second);
}
TCHAR startupBuffer[50];
ComboBox_GetText(m_hComboInitialisation, startupBuffer, 50);
configFile->setSetting(_T("STARTUP"), startupBuffer);
configFile->save();
}
void ShortcutDlg::toolbarSetIcon()
{
int index = ListView_GetNextItem(m_hListToolbarItems, -1, LVIS_SELECTED);
if (index != -1)
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = _hSelf;
tstring configDir(ConfigFile::getInstance()->getConfigDir());
configDir.append(_T("\\PythonScript\\icons"));
ofn.lpstrInitialDir = configDir.c_str();
//ofn.lpstrFileTitle = "Choose filename for new script";
ofn.lpstrFile = new TCHAR[MAX_PATH];
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = MAX_PATH;
//lint -e840 Use of nul character in a string literal
// This is how it's meant to be used.
ofn.lpstrFilter = _T("Icons (*.ico, *.bmp)\0*.ico;*.bmp\0All Files (*.*)\0*.*\0");
//lint +e840
ofn.nFilterIndex = 1;
ofn.Flags = OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
ConfigFile::ToolbarItemsTD::iterator it = m_toolbarItems.begin() + index;
it->second.first = static_cast<HBITMAP>(LoadImage(NULL, ofn.lpstrFile, IMAGE_BITMAP, 16, 16, LR_COLOR | LR_LOADFROMFILE));
it->second.second = ofn.lpstrFile;
int imageIndex = ImageList_Add(m_hImageList, it->second.first, NULL);
LVITEM lvItem;
lvItem.mask = LVIF_IMAGE;
lvItem.iItem = index;
lvItem.iImage = imageIndex;
ListView_SetItem(m_hListToolbarItems, &lvItem);
}
}
}