void ListView::init(HINSTANCE hInst, HWND parent)
{
	Window::init(hInst, parent);
    INITCOMMONCONTROLSEX icex;
    
    // Ensure that the common control DLL is loaded. 
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC  = ICC_LISTVIEW_CLASSES;
    InitCommonControlsEx(&icex);
    
    // Create the list-view window in report view with label editing enabled.
	int listViewStyles = LVS_REPORT | LVS_NOSORTHEADER\
						| LVS_SINGLESEL | LVS_AUTOARRANGE\
						| LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;

	_hSelf = ::CreateWindow(WC_LISTVIEW, 
                                TEXT(""), 
                                WS_CHILD | listViewStyles,
                                0,
                                0, 
                                0,
                                0,
                                _hParent, 
                                (HMENU) NULL, 
                                hInst,
                                NULL);
	if (!_hSelf)
	{
		throw std::runtime_error("ListView::init : CreateWindowEx() function return null");
	}

	::SetWindowLongPtr(_hSelf, GWLP_USERDATA, (LONG_PTR)this);
	_defaultProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hSelf, GWLP_WNDPROC, (LONG_PTR)staticProc));

	DWORD exStyle = ListView_GetExtendedListViewStyle(_hSelf);
	exStyle |= LVS_EX_FULLROWSELECT | LVS_EX_BORDERSELECT ;
	ListView_SetExtendedListViewStyle(_hSelf, exStyle);

	LVCOLUMN lvColumn;
	lvColumn.mask = LVCF_TEXT|LVCF_WIDTH;

	NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
	generic_string valStr = pNativeSpeaker->getAttrNameStr(TEXT("Value"), "AsciiInsertion", "ColumnVal");
	generic_string hexStr = pNativeSpeaker->getAttrNameStr(TEXT("Hex"), "AsciiInsertion", "ColumnHex");
	generic_string charStr = pNativeSpeaker->getAttrNameStr(TEXT("Character"), "AsciiInsertion", "ColumnChar");

	lvColumn.cx = 45;
	lvColumn.pszText = (TCHAR *)valStr.c_str();
	ListView_InsertColumn(_hSelf, 0, &lvColumn);
	
	lvColumn.cx = 45;
	lvColumn.pszText = (TCHAR *)hexStr.c_str();
	ListView_InsertColumn(_hSelf, 1, &lvColumn);

	lvColumn.cx = 70;
	lvColumn.pszText = (TCHAR *)charStr.c_str();
	ListView_InsertColumn(_hSelf, 2, &lvColumn);
}
void VerticalFileSwitcherListView::initList()
{
	TaskListInfo taskListInfo;
	static HWND nppHwnd = ::GetParent(_hParent);
	::SendMessage(nppHwnd, WM_GETTASKLISTINFO, (WPARAM)&taskListInfo, TRUE);

	NppParameters *nppParams = NppParameters::getInstance();
	NativeLangSpeaker *pNativeSpeaker = nppParams->getNativeLangSpeaker();
	
	bool isExtColumn = !nppParams->getNppGUI()._fileSwitcherWithoutExtColumn;
	
	RECT rc;
	::GetClientRect(_hParent, &rc);
	int totalWidth = rc.right - rc.left;

	generic_string nameStr = pNativeSpeaker->getAttrNameStr(TEXT("Name"), FS_ROOTNODE, FS_CLMNNAME);
	
	//insertColumn(nameStr.c_str(), 150, 0);
	insertColumn(nameStr.c_str(), (isExtColumn ? totalWidth - 50 : totalWidth), 0);

	//bool isExtColumn = !nppParams->getNppGUI()._fileSwitcherWithoutExtColumn;
	if (isExtColumn)
	{
		generic_string extStr = pNativeSpeaker->getAttrNameStr(TEXT("Ext."), FS_ROOTNODE, FS_CLMNEXT);
		insertColumn(extStr.c_str(), 50, 1);
	}

	for (size_t i = 0, len = taskListInfo._tlfsLst.size(); i < len ; ++i)
	{
		TaskLstFnStatus & fileNameStatus = taskListInfo._tlfsLst[i];

		TaskLstFnStatus *tl = new TaskLstFnStatus(fileNameStatus._iView, fileNameStatus._docIndex, fileNameStatus._fn, fileNameStatus._status, (void *)fileNameStatus._bufID);

		TCHAR fn[MAX_PATH];
		lstrcpy(fn, ::PathFindFileName(fileNameStatus._fn.c_str()));

		if (isExtColumn)
		{
			::PathRemoveExtension(fn);
		}
		LVITEM item;
		item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
		
		item.pszText = fn;
		item.iItem = static_cast<int32_t>(i);
		item.iSubItem = 0;
		item.iImage = fileNameStatus._status;
		item.lParam = (LPARAM)tl;
		ListView_InsertItem(_hSelf, &item);
		if (isExtColumn)
		{
			ListView_SetItemText(_hSelf, i, 1, (LPTSTR)::PathFindExtension(fileNameStatus._fn.c_str()));
		}
	}
	ListView_SetItemState(_hSelf, taskListInfo._currentIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
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::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::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;
    }
}
INT_PTR CALLBACK FunctionListPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
		// Make edit field red if not found
		case WM_CTLCOLOREDIT :
		{
			// if the text not found modify the background color of the editor
			static HBRUSH hBrushBackground = CreateSolidBrush(BCKGRD_COLOR);
			TCHAR text2search[MAX_PATH] ;
			::SendMessage(_hSearchEdit, WM_GETTEXT, MAX_PATH, reinterpret_cast<LPARAM>(text2search));
			if (text2search[0] == '\0')
			{
				return FALSE; // no text, use the default color
			}

			HTREEITEM searchViewRoot = _treeViewSearchResult.getRoot();
			if (searchViewRoot)
			{
				if (_treeViewSearchResult.getChildFrom(searchViewRoot))
					return FALSE; // children on root found, use the default color
			}
			else
				return FALSE; // no root (no parser), use the default color
			// text not found
			SetTextColor((HDC)wParam, TXT_COLOR);
			SetBkColor((HDC)wParam, BCKGRD_COLOR);
			return (LRESULT)hBrushBackground;
		}

        case WM_INITDIALOG :
        {
			int editWidth = NppParameters::getInstance()->_dpiManager.scaleX(100);
			int editWidthSep = NppParameters::getInstance()->_dpiManager.scaleX(105); //editWidth + 5
			int editHeight = NppParameters::getInstance()->_dpiManager.scaleY(20);

			// Create toolbar menu
			int style = WS_CHILD | WS_VISIBLE | CCS_ADJUSTABLE | TBSTYLE_AUTOSIZE | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | BTNS_AUTOSIZE | BTNS_SEP | TBSTYLE_TOOLTIPS;
			_hToolbarMenu = CreateWindowEx(0,TOOLBARCLASSNAME,NULL, style,
								   0,0,0,0,_hSelf,nullptr, _hInst, NULL);

			oldFunclstToolbarProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hToolbarMenu, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(funclstToolbarProc)));
			TBBUTTON tbButtons[3];

			// Add the bmap image into toolbar's imagelist
			TBADDBITMAP addbmp = {_hInst, 0};
			addbmp.nID = IDI_FUNCLIST_SORTBUTTON;
			::SendMessage(_hToolbarMenu, TB_ADDBITMAP, 1, reinterpret_cast<LPARAM>(&addbmp));
			addbmp.nID = IDI_FUNCLIST_RELOADBUTTON;
			::SendMessage(_hToolbarMenu, TB_ADDBITMAP, 1, reinterpret_cast<LPARAM>(&addbmp));

			// Place holder of search text field
			tbButtons[0].idCommand = 0;
			tbButtons[0].iBitmap = editWidthSep;
			tbButtons[0].fsState = TBSTATE_ENABLED;
			tbButtons[0].fsStyle = BTNS_SEP; //This is just a separator (blank space)
			tbButtons[0].iString = 0;

			tbButtons[1].idCommand = IDC_SORTBUTTON_FUNCLIST;
			tbButtons[1].iBitmap = 0;
			tbButtons[1].fsState = TBSTATE_ENABLED;
			tbButtons[1].fsStyle = BTNS_CHECK | BTNS_AUTOSIZE;
			tbButtons[1].iString = reinterpret_cast<INT_PTR>(TEXT(""));

			tbButtons[2].idCommand = IDC_RELOADBUTTON_FUNCLIST;
			tbButtons[2].iBitmap = 1;
			tbButtons[2].fsState = TBSTATE_ENABLED;
			tbButtons[2].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
			tbButtons[2].iString = reinterpret_cast<INT_PTR>(TEXT(""));

			::SendMessage(_hToolbarMenu, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
			::SendMessage(_hToolbarMenu, TB_SETBUTTONSIZE, 0, MAKELONG(16, 16));
			::SendMessage(_hToolbarMenu, TB_ADDBUTTONS, sizeof(tbButtons) / sizeof(TBBUTTON), reinterpret_cast<LPARAM>(&tbButtons));
			::SendMessage(_hToolbarMenu, TB_AUTOSIZE, 0, 0);

			ShowWindow(_hToolbarMenu, SW_SHOW);

			// tips text for toolbar buttons
			NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
			_sortTipStr = pNativeSpeaker->getAttrNameStr(_sortTipStr.c_str(), FL_FUCTIONLISTROOTNODE, FL_SORTLOCALNODENAME);
			_reloadTipStr = pNativeSpeaker->getAttrNameStr(_reloadTipStr.c_str(), FL_FUCTIONLISTROOTNODE, FL_RELOADLOCALNODENAME);

			_hSearchEdit = CreateWindowEx(0, L"Edit", NULL,
                                   WS_CHILD | WS_BORDER | WS_VISIBLE | ES_AUTOVSCROLL,
                                   2, 2, editWidth, editHeight,
                                   _hToolbarMenu, reinterpret_cast<HMENU>(IDC_SEARCHFIELD_FUNCLIST), _hInst, 0 );

			HFONT hf = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
			if (hf)
				::SendMessage(_hSearchEdit, WM_SETFONT, reinterpret_cast<WPARAM>(hf), MAKELPARAM(TRUE, 0));

			_treeViewSearchResult.init(_hInst, _hSelf, IDC_LIST_FUNCLIST_AUX);
			_treeView.init(_hInst, _hSelf, IDC_LIST_FUNCLIST);
			setTreeViewImageList(IDI_FUNCLIST_ROOT, IDI_FUNCLIST_NODE, IDI_FUNCLIST_LEAF);

			_treeView.display();
            return TRUE;
        }

		case WM_DESTROY:
			_treeView.destroy();
			_treeViewSearchResult.destroy();
			::DestroyWindow(_hToolbarMenu);
			break;

		case WM_COMMAND :
		{
			if (HIWORD(wParam) == EN_CHANGE)
			{
				switch (LOWORD(wParam))
				{
					case  IDC_SEARCHFIELD_FUNCLIST:
					{
						searchFuncAndSwitchView();
						return TRUE;
					}
				}
			}

			switch (LOWORD(wParam))
            {
				case IDC_SORTBUTTON_FUNCLIST:
				{
					sortOrUnsort();
				}
				return TRUE;

				case IDC_RELOADBUTTON_FUNCLIST:
				{
					reload();
				}
				return TRUE;
			}
		}
		break;

		case WM_NOTIFY:
		{
			notified((LPNMHDR)lParam);
		}
		return TRUE;

		case WM_SIZE:
		{
			int width = LOWORD(lParam);
			int height = HIWORD(lParam);
			int extraValue = NppParameters::getInstance()->_dpiManager.scaleX(4);

			RECT toolbarMenuRect;
			::GetClientRect(_hToolbarMenu, &toolbarMenuRect);

			::MoveWindow(_hToolbarMenu, 0, 0, width, toolbarMenuRect.bottom, TRUE);

			HWND hwnd = _treeView.getHSelf();
			if (hwnd)
				::MoveWindow(hwnd, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE);

			HWND hwnd_aux = _treeViewSearchResult.getHSelf();
			if (hwnd_aux)
				::MoveWindow(hwnd_aux, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE);

			break;
		}

		default :
			return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
	}
	return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
}