Example #1
0
BOOL Notepad_plus::notify(SCNotification *notification)
{
	//Important, keep track of which element generated the message
	bool isFromPrimary = (_mainEditView.getHSelf() == notification->nmhdr.hwndFrom || _mainDocTab.getHSelf() == notification->nmhdr.hwndFrom);
	bool isFromSecondary = !isFromPrimary && (_subEditView.getHSelf() == notification->nmhdr.hwndFrom || _subDocTab.getHSelf() == notification->nmhdr.hwndFrom);
	ScintillaEditView * notifyView = isFromPrimary?&_mainEditView:&_subEditView;
	DocTabView *notifyDocTab = isFromPrimary?&_mainDocTab:&_subDocTab;
	TBHDR * tabNotification = (TBHDR*) notification;
	switch (notification->nmhdr.code) 
	{
		case SCN_MODIFIED:
		{
			static bool prevWasEdit = false;
			if (notification->modificationType & (SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT))
			{
				_pEditView->updateBeginEndSelectPosition(notification->modificationType & SC_MOD_INSERTTEXT, notification->position, notification->length);
				prevWasEdit = true;
				_linkTriggered = true;
				::InvalidateRect(notifyView->getHSelf(), NULL, TRUE);
			}

			if (notification->modificationType & SC_MOD_CHANGEFOLD)
			{
				if (prevWasEdit) 
				{
					notifyView->foldChanged(notification->line,
							notification->foldLevelNow, notification->foldLevelPrev);
					prevWasEdit = false;
				}
			}
			else if (!(notification->modificationType & (SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT)))
			{
				prevWasEdit = false;
			}
		}
		break;

		case SCN_SAVEPOINTREACHED:
		case SCN_SAVEPOINTLEFT:
		{
			Buffer * buf = 0;
			if (isFromPrimary) {
				buf = _mainEditView.getCurrentBuffer();
			} else if (isFromSecondary) {
				buf = _subEditView.getCurrentBuffer();
			} else {
				//Done by invisibleEditView?
				BufferID id = BUFFER_INVALID;
				if (notification->nmhdr.hwndFrom == _invisibleEditView.getHSelf()) {
					id = MainFileManager->getBufferFromDocument(_invisibleEditView.execute(SCI_GETDOCPOINTER));
				} else if (notification->nmhdr.hwndFrom == _fileEditView.getHSelf()) {
					id = MainFileManager->getBufferFromDocument(_fileEditView.execute(SCI_GETDOCPOINTER));
				} else {
					break;	//wrong scintilla
				}
				if (id != BUFFER_INVALID) {
					buf = MainFileManager->getBufferByID(id);
				} else {
					break;
				}
			}
			bool isDirty = notification->nmhdr.code == SCN_SAVEPOINTLEFT;
			buf->setDirty(isDirty);
			break; 
		}

		case  SCN_MODIFYATTEMPTRO :
			// on fout rien
			break;

		case SCN_KEY:
			break;

	case TCN_TABDROPPEDOUTSIDE:
	case TCN_TABDROPPED:
	{
        TabBarPlus *sender = reinterpret_cast<TabBarPlus *>(notification->nmhdr.idFrom);
        bool isInCtrlStat = (::GetKeyState(VK_LCONTROL) & 0x80000000) != 0;
        if (notification->nmhdr.code == TCN_TABDROPPEDOUTSIDE)
        {
            POINT p = sender->getDraggingPoint();

			//It's the coordinate of screen, so we can call 
			//"WindowFromPoint" function without converting the point
            HWND hWin = ::WindowFromPoint(p);
			if (hWin == _pEditView->getHSelf()) // In the same view group
			{
				if (!_tabPopupDropMenu.isCreated())
				{
					TCHAR goToView[32] = TEXT("Move to other view");
					TCHAR cloneToView[32] = TEXT("Clone to other View");
					vector<MenuItemUnit> itemUnitArray;
					itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_ANOTHER_VIEW, goToView));
					itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_CLONE_TO_ANOTHER_VIEW, cloneToView));
					_tabPopupDropMenu.create(_pPublicInterface->getHSelf(), itemUnitArray, _mainMenuHandle);
					_nativeLangSpeaker.changeLangTabDrapContextMenu(_tabPopupDropMenu.getMenuHandle());
				}
				_tabPopupDropMenu.display(p);
			}
			else if ((hWin == _pNonDocTab->getHSelf()) || 
				     (hWin == _pNonEditView->getHSelf())) // In the another view group
			{
                docGotoAnotherEditView(isInCtrlStat?TransferClone:TransferMove);
			}/*
			else if ((hWin == _pProjectPanel_1->getTreeHandle()))
			{
				
                //printStr(TEXT("IN!!!"));
			}*/
			else
			{
				RECT nppZone;
				::GetWindowRect(_pPublicInterface->getHSelf(), &nppZone);
				bool isInNppZone = (((p.x >= nppZone.left) && (p.x <= nppZone.right)) && (p.y >= nppZone.top) && (p.y <= nppZone.bottom));
				if (isInNppZone)
				{
					// Do nothing
					return TRUE;
				}
				generic_string quotFileName = TEXT("\"");
				quotFileName += _pEditView->getCurrentBuffer()->getFullPathName();
				quotFileName += TEXT("\"");
				COPYDATASTRUCT fileNamesData;
				fileNamesData.dwData = COPYDATA_FILENAMES;
				fileNamesData.lpData = (void *)quotFileName.c_str();
				fileNamesData.cbData = long(quotFileName.length() + 1)*(sizeof(TCHAR));

				HWND hWinParent = ::GetParent(hWin);
				TCHAR className[MAX_PATH];
				::GetClassName(hWinParent,className, sizeof(className));
				if (lstrcmp(className, _pPublicInterface->getClassName()) == 0 && hWinParent != _pPublicInterface->getHSelf()) // another Notepad++
				{
					int index = _pDocTab->getCurrentTabIndex();
					BufferID bufferToClose = notifyDocTab->getBufferByIndex(index);
					Buffer * buf = MainFileManager->getBufferByID(bufferToClose);
					int iView = isFromPrimary?MAIN_VIEW:SUB_VIEW;
					if (buf->isDirty()) 
					{
						generic_string msg, title;
						_nativeLangSpeaker.messageBox("CannotMoveDoc",
							_pPublicInterface->getHSelf(),
							TEXT("Document is modified, save it then try again."),
							TEXT("Move to new Notepad++ Instance"),
							MB_OK);
					}
					else
					{
						::SendMessage(hWinParent, NPPM_INTERNAL_SWITCHVIEWFROMHWND, 0, (LPARAM)hWin);
						::SendMessage(hWinParent, WM_COPYDATA, (WPARAM)_pPublicInterface->getHinst(), (LPARAM)&fileNamesData);
                        if (!isInCtrlStat)
						{
							fileClose(bufferToClose, iView);
							if (noOpenedDoc())
								::SendMessage(_pPublicInterface->getHSelf(), WM_CLOSE, 0, 0);
						}
					}
				}
                else // Not Notepad++, we open it here
                {
					docOpenInNewInstance(isInCtrlStat?TransferClone:TransferMove, p.x, p.y);
                }
			}
        }
		//break;
		sender->resetDraggingPoint();
		return TRUE;
	}

	case TCN_TABDELETE:
	{
		int index = tabNotification->tabOrigin;
		BufferID bufferToClose = notifyDocTab->getBufferByIndex(index);
		Buffer * buf = MainFileManager->getBufferByID(bufferToClose);
		int iView = isFromPrimary?MAIN_VIEW:SUB_VIEW;
		if (buf->isDirty()) {	//activate and use fileClose() (for save and abort)
			activateBuffer(bufferToClose, iView);
			fileClose(bufferToClose, iView);
			break;
		}
		int open = 1;
		if (isFromPrimary || isFromSecondary)
			open = notifyDocTab->nbItem();
		doClose(bufferToClose, iView);
		//if (open == 1 && canHideView(iView))
		//	hideView(iView);
		break;

	}

	case TCN_SELCHANGE:
	{
		int iView = -1;
        if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf())
		{
			iView = MAIN_VIEW;
		}
		else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf())
		{
			iView = SUB_VIEW;
		}
		else
		{
			break;
		}

		switchEditViewTo(iView);
		BufferID bufid = _pDocTab->getBufferByIndex(_pDocTab->getCurrentTabIndex());
		if (bufid != BUFFER_INVALID)
			activateBuffer(bufid, iView);
		
		break;
	}

	case NM_CLICK :
    {        
		if (notification->nmhdr.hwndFrom == _statusBar.getHSelf())
        {
            LPNMMOUSE lpnm = (LPNMMOUSE)notification;
			if (lpnm->dwItemSpec == DWORD(STATUSBAR_TYPING_MODE))
			{
				bool isOverTypeMode = (_pEditView->execute(SCI_GETOVERTYPE) != 0);
				_pEditView->execute(SCI_SETOVERTYPE, !isOverTypeMode);
				_statusBar.setText((_pEditView->execute(SCI_GETOVERTYPE))?TEXT("OVR"):TEXT("INS"), STATUSBAR_TYPING_MODE);
			}
        }
		else if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf())
		{
            switchEditViewTo(MAIN_VIEW);
		}
        else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf())
        {
            switchEditViewTo(SUB_VIEW);
        }

		break;
	}

	case NM_DBLCLK :
    {        
		if (notification->nmhdr.hwndFrom == _statusBar.getHSelf())
        {
            LPNMMOUSE lpnm = (LPNMMOUSE)notification;
			if (lpnm->dwItemSpec == DWORD(STATUSBAR_CUR_POS))
			{
				bool isFirstTime = !_goToLineDlg.isCreated();
                _goToLineDlg.doDialog(_nativeLangSpeaker.isRTL());
				if (isFirstTime)
                    _nativeLangSpeaker.changeDlgLang(_goToLineDlg.getHSelf(), "GoToLine");
			}
            else if (lpnm->dwItemSpec == DWORD(STATUSBAR_DOC_SIZE))
			{
				command(IDM_VIEW_SUMMARY);
			}
        }
		break;
	}

    case NM_RCLICK :
    {
		POINT p;
		::GetCursorPos(&p);

		if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf())
		{
            switchEditViewTo(MAIN_VIEW);
		}
        else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf())
        {
            switchEditViewTo(SUB_VIEW);
        }
		else if (_pFileSwitcherPanel && notification->nmhdr.hwndFrom == _pFileSwitcherPanel->getHSelf())
        {
			// Already switched, so do nothing here.

			if (_pFileSwitcherPanel->nbSelectedFiles() > 1)
			{
				if (!_fileSwitcherMultiFilePopupMenu.isCreated())
				{
					vector<MenuItemUnit> itemUnitArray;
					itemUnitArray.push_back(MenuItemUnit(IDM_FILESWITCHER_FILESCLOSE, TEXT("Close Selected files")));
					itemUnitArray.push_back(MenuItemUnit(IDM_FILESWITCHER_FILESCLOSEOTHERS, TEXT("Close others files")));

					_fileSwitcherMultiFilePopupMenu.create(_pPublicInterface->getHSelf(), itemUnitArray);
					_nativeLangSpeaker.changeLangTabContextMenu(_fileSwitcherMultiFilePopupMenu.getMenuHandle());
				}
				_fileSwitcherMultiFilePopupMenu.display(p);
				return TRUE;
			}
		}
		else // From tool bar or Status Bar
			return TRUE;
			//break;

		if (!_tabPopupMenu.isCreated())
		{
			vector<MenuItemUnit> itemUnitArray;
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSE, TEXT("Close")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_BUT_CURRENT, TEXT("Close All BUT This")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_TOLEFT, TEXT("Close All to the Left")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_TORIGHT, TEXT("Close All to the Right")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_SAVE, TEXT("Save")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_SAVEAS, TEXT("Save As...")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_RENAME, TEXT("Rename")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_DELETE, TEXT("Move to Recycle Bin")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_RELOAD, TEXT("Reload")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_PRINT, TEXT("Print")));
			itemUnitArray.push_back(MenuItemUnit(0, NULL));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_FOLDER, TEXT("Open Containing Folder in Explorer")));
			itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_CMD, TEXT("Open Containing Folder in cmd")));
			itemUnitArray.push_back(MenuItemUnit(0, NULL));
			itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_SETREADONLY, TEXT("Read-Only")));
			itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_CLEARREADONLY, TEXT("Clear Read-Only Flag")));
			itemUnitArray.push_back(MenuItemUnit(0, NULL));
			itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_FULLPATHTOCLIP,	TEXT("Full File Path to Clipboard")));
			itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_FILENAMETOCLIP,   TEXT("Filename to Clipboard")));
			itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_CURRENTDIRTOCLIP, TEXT("Current Dir. Path to Clipboard")));
			itemUnitArray.push_back(MenuItemUnit(0, NULL));
			itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_ANOTHER_VIEW, TEXT("Move to Other View")));
			itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_CLONE_TO_ANOTHER_VIEW, TEXT("Clone to Other View")));
			itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_NEW_INSTANCE, TEXT("Move to New Instance")));
			itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_LOAD_IN_NEW_INSTANCE, TEXT("Open in New Instance")));

			_tabPopupMenu.create(_pPublicInterface->getHSelf(), itemUnitArray);
            _nativeLangSpeaker.changeLangTabContextMenu(_tabPopupMenu.getMenuHandle());
		}

		bool isEnable = ((::GetMenuState(_mainMenuHandle, IDM_FILE_SAVE, MF_BYCOMMAND)&MF_DISABLED) == 0);
		_tabPopupMenu.enableItem(IDM_FILE_SAVE, isEnable);
		
		Buffer * buf = _pEditView->getCurrentBuffer();
		bool isUserReadOnly = buf->getUserReadOnly();
		_tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly);

		bool isSysReadOnly = buf->getFileReadOnly();
		_tabPopupMenu.enableItem(IDM_EDIT_SETREADONLY, !isSysReadOnly);
		_tabPopupMenu.enableItem(IDM_EDIT_CLEARREADONLY, isSysReadOnly);

		bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE;
		_tabPopupMenu.enableItem(IDM_FILE_DELETE, isFileExisting);
		_tabPopupMenu.enableItem(IDM_FILE_RENAME, isFileExisting);

		bool isDirty = buf->isDirty();
		bool isUntitled = buf->isUntitled();
		_tabPopupMenu.enableItem(IDM_VIEW_GOTO_NEW_INSTANCE, !(isDirty||isUntitled));
		_tabPopupMenu.enableItem(IDM_VIEW_LOAD_IN_NEW_INSTANCE, !(isDirty||isUntitled));

		_tabPopupMenu.display(p);
		return TRUE;
    }

    
	case SCN_MARGINCLICK:
    {
        if (notification->nmhdr.hwndFrom == _mainEditView.getHSelf())
            switchEditViewTo(MAIN_VIEW);
		else if (notification->nmhdr.hwndFrom == _subEditView.getHSelf())
            switchEditViewTo(SUB_VIEW);

        int lineClick = int(_pEditView->execute(SCI_LINEFROMPOSITION, notification->position));
        
		if (notification->margin == ScintillaEditView::_SC_MARGE_FOLDER)
        {
            _pEditView->marginClick(notification->position, notification->modifiers);
			if (_pDocMap)
				_pDocMap->fold(lineClick, _pEditView->isFolded(lineClick));
        }
        else if ((notification->margin == ScintillaEditView::_SC_MARGE_SYBOLE) && !notification->modifiers)
        {
			if (!_pEditView->markerMarginClick(lineClick))
				bookmarkToggle(lineClick);
        }
		break;
	}

	case SCN_FOLDINGSTATECHANGED :
	{
		if ((notification->nmhdr.hwndFrom == _mainEditView.getHSelf())
		|| (notification->nmhdr.hwndFrom == _subEditView.getHSelf()))
		{
			int lineClicked = notification->line;
			
			if (!_isFolding)
			{
				int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL;
				if ((urlAction == 1) || (urlAction == 2))
					addHotSpot();
			}

			if (_pDocMap)
				_pDocMap->fold(lineClicked, _pEditView->isFolded(lineClicked));
		}
		return TRUE;
	}

	case SCN_CHARADDED:
	{
		const NppGUI & nppGui = NppParameters::getInstance()->getNppGUI();
		bool indentMaintain = nppGui._maitainIndent;
		if (indentMaintain)
			MaintainIndentation(static_cast<TCHAR>(notification->ch));
		
		AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
		
		if (nppGui._matchedPairConf.hasAnyPairsPair())
			autoC->insertMatchedChars(notification->ch, nppGui._matchedPairConf);
		autoC->update(notification->ch);

		break;
	}

	case SCN_DOUBLECLICK :
	{
		if(notification->modifiers == SCMOD_CTRL)
		{
			const NppGUI & nppGUI = NppParameters::getInstance()->getNppGUI();

			std::string bufstring;
			unsigned int position_of_click;

			// Anonymous scope to limit use of the buf pointer (much easier to deal with std::string).
			{
				char *buf;
				int length;
				
				if(nppGUI._delimiterSelectionOnEntireDocument)
				{
					// Get entire document.
					length = notifyView->execute(SCI_GETLENGTH);
					buf = new char[length + 1];
					notifyView->execute(SCI_GETTEXT, (LPARAM)(length + 1), (WPARAM)buf);

					// For some reason Ctrl+DoubleClick on an empty line means that notification->position == 1.
					// In that case we use SCI_GETCURRENTPOS to get the position.
					if(notification->position != -1)
						position_of_click = notification->position;
					else
						position_of_click = int(_pEditView->execute(SCI_GETCURRENTPOS));
				}
				else
				{
					// Get single line.
					length = notifyView->execute(SCI_GETCURLINE);
					buf = new char[length + 1];
					notifyView->execute(SCI_GETCURLINE, (WPARAM)length, (LPARAM)buf);

					// Compute the position of the click (relative to the beginning of the line).
					const int line_position = notifyView->execute(SCI_POSITIONFROMLINE, notifyView->getCurrentLineNumber());
					position_of_click = notification->position - line_position;
				}

				bufstring = buf;
				delete [] buf;
			}

			int leftmost_position = -1;
			int rightmost_position = -1;

			if(nppGUI._rightmostDelimiter == nppGUI._leftmostDelimiter)
			{
				// If the delimiters are the same (e.g. they are both a quotation mark), choose the ones
				// which are closest to the clicked position.

				for(unsigned int i = position_of_click; i >= 0; --i)
				{
					if(bufstring.at(i) == nppGUI._leftmostDelimiter)
					{
						// Respect escaped quotation marks.
						if(nppGUI._leftmostDelimiter == '"')
						{
							if(! (i > 0 && bufstring.at(i - 1) == '\\'))
							{
								leftmost_position = i;
								break;
							}
						}
						else
						{
							leftmost_position = i;
							break;
						}
					}
				}

				if(leftmost_position == -1)
					break;

				// Scan for right delimiter.
				for(unsigned int i = position_of_click; i < bufstring.length(); ++i)
				{
					if(bufstring.at(i) == nppGUI._rightmostDelimiter)
					{
						// Respect escaped quotation marks.
						if(nppGUI._rightmostDelimiter == '"')
						{
							if(! (i > 0 && bufstring.at(i - 1) == '\\'))
							{
								rightmost_position = i;
								break;
							}
						}
						else
						{
							rightmost_position = i;
							break;
						}
					}
				}
			}
			else
			{
				// Find matching pairs of delimiters (e.g. parantheses).
				// The pair where the distance from the left delimiter to position_of_click is at a minimum is the one we're looking for.
				// Of course position_of_click must lie between the delimiters.

				// This logic is required to handle cases like this:
				// (size_t i = function(); i < _buffers.size(); i++)

				std::stack<unsigned int> leftmost_delimiter_positions;

				for(unsigned int i = 0; i < bufstring.length(); ++i)
				{
					if(bufstring.at(i) == nppGUI._leftmostDelimiter)
						leftmost_delimiter_positions.push(i);
					else if(bufstring.at(i) == nppGUI._rightmostDelimiter && ! leftmost_delimiter_positions.empty())
					{
						unsigned int matching_leftmost = leftmost_delimiter_positions.top();
						leftmost_delimiter_positions.pop();

						// We have either 1) chosen neither the left- or rightmost position, or 2) chosen both left- and rightmost position.
						assert( (leftmost_position == -1 && rightmost_position == -1) || (leftmost_position >= 0 && rightmost_position >= 0) );

						// Note: cast of leftmost_position to unsigned int is safe, since if leftmost_position is not -1 then it is guaranteed to be positive.
						// If it was possible, leftmost_position and rightmost_position should be of type optional<unsigned int>.
						if( matching_leftmost <= position_of_click && i >= position_of_click &&  (leftmost_position == -1 ||  matching_leftmost > (unsigned int)leftmost_position) )
						{
							leftmost_position = matching_leftmost;
							rightmost_position = i;
						}
					}
				}
			}

			// Set selection to the position we found (if any).
			if(rightmost_position != -1 && leftmost_position != -1)
			{
				if(nppGUI._delimiterSelectionOnEntireDocument)
				{
					notifyView->execute(SCI_SETCURRENTPOS, rightmost_position);
					notifyView->execute(SCI_SETANCHOR, leftmost_position + 1);
				}
				else
				{
					const int line_position = notifyView->execute(SCI_POSITIONFROMLINE, notifyView->getCurrentLineNumber());
					notifyView->execute(SCI_SETCURRENTPOS, line_position + rightmost_position);
					notifyView->execute(SCI_SETANCHOR, line_position + leftmost_position + 1);
				}
			}
		}
		else if (_isHotspotDblClicked)
		{
			int pos = notifyView->execute(SCI_GETCURRENTPOS);
			notifyView->execute(SCI_SETCURRENTPOS, pos);
			notifyView->execute(SCI_SETANCHOR, pos);
			_isHotspotDblClicked = false;
		}
	}
	break;

	case SCN_UPDATEUI:
	{
		NppParameters *nppParam = NppParameters::getInstance();

		// replacement for obsolete custom SCN_SCROLLED
		if (notification->updated & SC_UPDATE_V_SCROLL)
		{
			int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL;
			if ((urlAction == 1) || (urlAction == 2))
				addHotSpot();
		}

		// if it's searching/replacing, then do nothing
		if (nppParam->_isFindReplacing)
			break;

		if (notification->nmhdr.hwndFrom != _pEditView->getHSelf())
			break;
		
        braceMatch();

		NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI();

		if (nppGui._enableTagsMatchHilite)
		{
			XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView);
			xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite);
		}
		
		if (nppGui._enableSmartHilite)
		{
			if (nppGui._disableSmartHiliteTmp)
				nppGui._disableSmartHiliteTmp = false;
			else
				_smartHighlighter.highlightView(notifyView);
		}

		updateStatusBar();
		AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
		autoC->update(0);

        break;
	}

    case TTN_GETDISPINFO:
    {
		try {
			LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)notification; 

			//Joce's fix
			lpttt->hinst = NULL; 

			POINT p;
			::GetCursorPos(&p);
			::ScreenToClient(_pPublicInterface->getHSelf(), &p);
			HWND hWin = ::RealChildWindowFromPoint(_pPublicInterface->getHSelf(), p);
			const int tipMaxLen = 1024;
			static TCHAR docTip[tipMaxLen];
			docTip[0] = '\0';

			generic_string tipTmp(TEXT(""));
			int id = int(lpttt->hdr.idFrom);

			if (hWin == _rebarTop.getHSelf())
			{
				getNameStrFromCmd(id, tipTmp);
				if (tipTmp.length() >= 80)
					return FALSE;

				lstrcpy(lpttt->szText, tipTmp.c_str());
				return TRUE;
			}
			else if (hWin == _mainDocTab.getHSelf())
			{
				BufferID idd = _mainDocTab.getBufferByIndex(id);
				Buffer * buf = MainFileManager->getBufferByID(idd);
				tipTmp = buf->getFullPathName();

				if (tipTmp.length() >= tipMaxLen)
					return FALSE;
				lstrcpy(docTip, tipTmp.c_str());
				lpttt->lpszText = docTip;
				return TRUE;
			}
			else if (hWin == _subDocTab.getHSelf())
			{
				BufferID idd = _subDocTab.getBufferByIndex(id);
				Buffer * buf = MainFileManager->getBufferByID(idd);
				tipTmp = buf->getFullPathName();

				if (tipTmp.length() >= tipMaxLen)
					return FALSE;
				lstrcpy(docTip, tipTmp.c_str());
				lpttt->lpszText = docTip;
				return TRUE;
			}
			else
			{
				return FALSE;
			}
		} catch (...) {
			//printStr(TEXT("ToolTip crash is caught!"));
		}
    }
	break;


    case SCN_ZOOM:
		break;

    case SCN_MACRORECORD:
        _macro.push_back(recordedMacroStep(notification->message, notification->wParam, notification->lParam, _pEditView->execute(SCI_GETCODEPAGE)));
		break;

	case SCN_PAINTED:
	{
		//--FLS: ViewMoveAtWrappingDisableFix: Disable wrapping messes up visible lines. Therefore save view position before in IDM_VIEW_WRAP and restore after SCN_PAINTED, as doc. says
		if (_mainEditView.isWrapRestoreNeeded())
		{
			_mainEditView.restoreCurrentPos();
			_mainEditView.setWrapRestoreNeeded(false);
		}

		if (_subEditView.isWrapRestoreNeeded())
		{
			_subEditView.restoreCurrentPos();
			_subEditView.setWrapRestoreNeeded(false);
		}
		notifyView->updateLineNumberWidth();
		if (_syncInfo.doSync()) 
			doSynScorll(HWND(notification->nmhdr.hwndFrom));

		NppParameters *nppParam = NppParameters::getInstance();
		
		// if it's searching/replacing, then do nothing
		if ((_linkTriggered && !nppParam->_isFindReplacing) || notification->wParam == LINKTRIGGERED)
		{
			int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL;
			if ((urlAction == 1) || (urlAction == 2))
				addHotSpot();
			_linkTriggered = false;
		}

		if (_pDocMap)
		{
			_pDocMap->wrapMap();
			_pDocMap->scrollMap();
		}
		break;
	}

	case SCN_HOTSPOTDOUBLECLICK :
	{
		notifyView->execute(SCI_SETWORDCHARS, 0, (LPARAM)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+.,:?&@=/%#()");
		
		int pos = notifyView->execute(SCI_GETCURRENTPOS);
		int startPos = static_cast<int>(notifyView->execute(SCI_WORDSTARTPOSITION, pos, false));
		int endPos = static_cast<int>(notifyView->execute(SCI_WORDENDPOSITION, pos, false));

		notifyView->execute(SCI_SETTARGETSTART, startPos);
		notifyView->execute(SCI_SETTARGETEND, endPos);
	
		int posFound = notifyView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), (LPARAM)URL_REG_EXPR);
		if (posFound != -2)
		{
			if (posFound != -1)
			{
				startPos = int(notifyView->execute(SCI_GETTARGETSTART));
				endPos = int(notifyView->execute(SCI_GETTARGETEND));
			}

			// Prevent buffer overflow in getGenericText().
			if(endPos - startPos > 2*MAX_PATH)
				endPos = startPos + 2*MAX_PATH;

			TCHAR currentWord[2*MAX_PATH];

			notifyView->getGenericText(currentWord, MAX_PATH*2, startPos, endPos);

			// This treatment would fail on some valid URLs where there's actually supposed to be a comma or parenthesis at the end.
			int lastCharIndex = _tcsnlen(currentWord, MAX_PATH*2) - 1;
			if(lastCharIndex >= 0 && (currentWord[lastCharIndex] == ',' || currentWord[lastCharIndex] == ')' || currentWord[lastCharIndex] == '('))
				currentWord[lastCharIndex] = '\0';

			::ShellExecute(_pPublicInterface->getHSelf(), TEXT("open"), currentWord, NULL, NULL, SW_SHOW);
			_isHotspotDblClicked = true;
			notifyView->execute(SCI_SETCHARSDEFAULT);
		}
		break;
	}

	case SCN_NEEDSHOWN :
	{
		int begin = notifyView->execute(SCI_LINEFROMPOSITION, notification->position);
		int end = notifyView->execute(SCI_LINEFROMPOSITION, notification->position + notification->length);
		int firstLine = begin < end ? begin : end;
		int lastLine = begin > end ? begin : end;
		for (int line = firstLine; line <= lastLine; ++line)
		{
			notifyView->execute(SCI_ENSUREVISIBLE, line, 0);
		}
		break;
	}

	case SCN_CALLTIPCLICK:
	{
		AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
		autoC->callTipClick(notification->position);
		break;
	}

	case RBN_HEIGHTCHANGE:
	{
		SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
		break;
	}
	case RBN_CHEVRONPUSHED:
	{
		NMREBARCHEVRON * lpnm = (NMREBARCHEVRON*) notification;
		ReBar * notifRebar = &_rebarTop;
		if (_rebarBottom.getHSelf() == lpnm->hdr.hwndFrom)
			notifRebar = &_rebarBottom;
		//If N++ ID, use proper object
		switch(lpnm->wID) {
			case REBAR_BAR_TOOLBAR: {
				POINT pt;
				pt.x = lpnm->rc.left;
				pt.y = lpnm->rc.bottom;
				ClientToScreen(notifRebar->getHSelf(), &pt);
				_toolBar.doPopop(pt);
				return TRUE;
				break; }
		}
		//Else forward notification to window of rebarband
		REBARBANDINFO rbBand;
		ZeroMemory(&rbBand, REBARBAND_SIZE);
		rbBand.cbSize  = REBARBAND_SIZE;

		rbBand.fMask = RBBIM_CHILD;
		::SendMessage(notifRebar->getHSelf(), RB_GETBANDINFO, lpnm->uBand, (LPARAM)&rbBand);
		::SendMessage(rbBand.hwndChild, WM_NOTIFY, 0, (LPARAM)lpnm);
		break;
	}

	default :
		break;

  }
  return FALSE;
}
BOOL CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_INITDIALOG :
		{
			initBabyGrid();
			initTabs();
			fillOutBabyGrid();
			_babygrid.display();	
			goToCenter();
			return TRUE;
		}

		case WM_NOTIFY: {
			NMHDR nmh = *((NMHDR*)lParam);
			if (nmh.hwndFrom == _hTabCtrl) {
				if (nmh.code == TCN_SELCHANGE) {
					int index = TabCtrl_GetCurSel(_hTabCtrl);
					switch (index) {
						case 0:
							_currentState = STATE_MENU;
							break;
						case 1:
							_currentState = STATE_MACRO;
							break;
						case 2:
							_currentState = STATE_USER;
							break;
						case 3:
							_currentState = STATE_PLUGIN;
							break;
						case 4:
							_currentState = STATE_SCINTILLA;
							break;
					}
					fillOutBabyGrid();
				}
			}
			break; }

		case WM_COMMAND : 
		{
			switch (LOWORD(wParam))
			{
				case IDCANCEL :
				{
					::EndDialog(_hSelf, -1);
					return TRUE;
				}
				case IDOK :
				{
					::EndDialog(_hSelf, 0);
					return TRUE;
				}

				case IDM_BABYGRID_MODIFY :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					int row = _babygrid.getSelectedRow();

					switch(_currentState) {
						case STATE_MENU: {
							//Get CommandShortcut corresponding to row
							vector<CommandShortcut> & shortcuts = nppParam->getUserShortcuts();
							CommandShortcut csc = shortcuts[row - 1], prevcsc = shortcuts[row - 1];
							csc.init(_hInst, _hSelf);
							if (csc.doDialog() != -1 && prevcsc != csc) {	//shortcut was altered
								nppParam->addUserModifiedIndex(row-1);
								shortcuts[row - 1] = csc;
								_babygrid.setText(row, 2, csc.toString().c_str());
								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								
							}
							break; }
						case STATE_MACRO: {
							//Get MacroShortcut corresponding to row
							vector<MacroShortcut> & shortcuts = nppParam->getMacroList();
							MacroShortcut msc = shortcuts[row - 1], prevmsc = shortcuts[row - 1];
							msc.init(_hInst, _hSelf);
							if (msc.doDialog() != -1 && prevmsc != msc) {	//shortcut was altered
								shortcuts[row - 1] = msc;
								_babygrid.setText(row, 1, msc.getName());
								_babygrid.setText(row, 2, msc.toString().c_str());

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								
							}
							break; }
						case STATE_USER: {
							//Get UserCommand corresponding to row
							vector<UserCommand> & shortcuts = nppParam->getUserCommandList();
							UserCommand ucmd = shortcuts[row - 1], prevucmd = shortcuts[row - 1];
							ucmd.init(_hInst, _hSelf);
							prevucmd = ucmd;
							if (ucmd.doDialog() != -1 && prevucmd != ucmd) {	//shortcut was altered
								shortcuts[row - 1] = ucmd;
								_babygrid.setText(row, 1, ucmd.getName());
								_babygrid.setText(row, 2, ucmd.toString().c_str());

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								
							}
							break; }
						case STATE_PLUGIN: {
							//Get PluginCmdShortcut corresponding to row
							vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList();
							PluginCmdShortcut pcsc = shortcuts[row - 1], prevpcsc = shortcuts[row - 1];
							pcsc.init(_hInst, _hSelf);
							prevpcsc = pcsc;
							if (pcsc.doDialog() != -1 && prevpcsc != pcsc) {	//shortcut was altered
								nppParam->addPluginModifiedIndex(row-1);
								shortcuts[row - 1] = pcsc;
								_babygrid.setText(row, 2, pcsc.toString().c_str());

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								unsigned long cmdID = pcsc.getID();
								ShortcutKey shortcut;
								shortcut._isAlt = pcsc.getKeyCombo()._isAlt;
								shortcut._isCtrl = pcsc.getKeyCombo()._isCtrl;
								shortcut._isShift = pcsc.getKeyCombo()._isShift;
								shortcut._key = pcsc.getKeyCombo()._key;

								::SendMessage(_hParent, NPPM_INTERNAL_PLUGINSHORTCUTMOTIFIED, cmdID, (LPARAM)&shortcut);
							}
							break; }
						case STATE_SCINTILLA: {
							//Get ScintillaKeyMap corresponding to row
							vector<ScintillaKeyMap> & shortcuts = nppParam->getScintillaKeyList();
							ScintillaKeyMap skm = shortcuts[row - 1], prevskm = shortcuts[row-1];
							skm.init(_hInst, _hSelf);
							if (skm.doDialog() != -1 && prevskm != skm) 
							{
								//shortcut was altered
								nppParam->addScintillaModifiedIndex(row-1);
								shortcuts[row-1] = skm;
								_babygrid.setText(row, 2, skm.toString().c_str());

								//Notify current Accelerator class to update key
								nppParam->getScintillaAccelerator()->updateKeys();
							}
							break; 
						}
					}
					return TRUE;
				}
				case IDM_BABYGRID_DELETE :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					if (::MessageBox(_hSelf, TEXT("Are you sure you want to delete this shortcut?"), TEXT("Are you sure?"), MB_OKCANCEL) == IDOK)
					{
						const int row = _babygrid.getSelectedRow();
						int shortcutIndex = row-1;
						DWORD cmdID = 0;
						
						// Menu data
						size_t posBase = 0;
						size_t nbElem = 0;
						HMENU hMenu = NULL;
                        int modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN;
						switch(_currentState) 
						{
							case STATE_MENU:
							case STATE_PLUGIN:
							case STATE_SCINTILLA: 
							{
								return FALSE;			//this is bad
							}
							case STATE_MACRO: 
							{
								vector<MacroShortcut> & theMacros = nppParam->getMacroList();
								vector<MacroShortcut>::iterator it = theMacros.begin();
								cmdID = theMacros[shortcutIndex].getID();
								theMacros.erase(it + shortcutIndex);
								fillOutBabyGrid();
								
								// preparing to remove from menu
								posBase = 6;
								nbElem = theMacros.size();
								hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_MACRO);
                                modifCmd = IDM_SETTING_SHORTCUT_MAPPER_MACRO;
								for (size_t i = shortcutIndex ; i < nbElem ; i++)	//lower the IDs of the remaining items so there are no gaps
								{
									MacroShortcut ms = theMacros[i];
									ms.setID(ms.getID() - 1);	//shift all IDs
									theMacros[i] = ms;
								}
								break; 
							}
							case STATE_USER: 
							{
								vector<UserCommand> & theUserCmds = nppParam->getUserCommandList();
								vector<UserCommand>::iterator it = theUserCmds.begin();
								cmdID = theUserCmds[shortcutIndex].getID();
								theUserCmds.erase(it + shortcutIndex);
								fillOutBabyGrid();
							
								// preparing to remove from menu
								posBase = 2;
								nbElem = theUserCmds.size();
								hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_RUN);
                                modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN;
								for (size_t i = shortcutIndex ; i < nbElem ; i++)	//lower the IDs of the remaining items so there are no gaps
								{
									UserCommand uc = theUserCmds[i];
									uc.setID(uc.getID() - 1);	//shift all IDs
									theUserCmds[i] = uc;
								}
								break;
							}
						}

                        // updateShortcuts() will update all menu item - the menu items will be shifted
						nppParam->getAccelerator()->updateShortcuts();

                        // All menu items are shifted up. So we delete the last item
                        ::RemoveMenu(hMenu, posBase + nbElem - 1, MF_BYPOSITION);

                        if (nbElem == 0) 
                        {
                            ::RemoveMenu(hMenu, modifCmd, MF_BYCOMMAND);
                            
                            //remove separator
							::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION);
                            ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION);
						}
					}
					return TRUE;
				}

				case IDD_BABYGRID_ID1: {
					if(HIWORD(wParam) == BGN_CELLDBCLICKED) //a cell was clicked in the properties grid
					{
						return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_MODIFY, LOWORD(lParam));
					}
					else if(HIWORD(wParam) == BGN_CELLRCLICKED) //a cell was clicked in the properties grid
					{
						POINT p;
						::GetCursorPos(&p);
						if (!_rightClickMenu.isCreated())
						{
							vector<MenuItemUnit> itemUnitArray;
							itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_MODIFY, TEXT("Modify")));
							itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_DELETE, TEXT("Delete")));
							_rightClickMenu.create(_hSelf, itemUnitArray);
						}
						switch(_currentState) {
							case STATE_MACRO:
							case STATE_USER: {
								_rightClickMenu.enableItem(IDM_BABYGRID_DELETE, true);
								break; }
							case STATE_MENU:
							case STATE_PLUGIN:
							case STATE_SCINTILLA: {
								_rightClickMenu.enableItem(IDM_BABYGRID_DELETE, false);
								break; }
						}
						
						_rightClickMenu.display(p);
						return TRUE;
					}
				}
			}
		}
		default:
			return FALSE;
	}
	return FALSE;
}
Example #3
0
BOOL CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_INITDIALOG :
		{
			initTabs();
			initList();
			populateShortCuts();
			goToCenter();
			GetWindowRect(_hSelf,&default_sm_size);
			AnchorInit(_hSelf,ShortcutAnchors,sizeof(ShortcutAnchors)/sizeof(CONTROL_ANCHOR));
			RestoreWinRelPosition(_hParent,_hSelf,&WinRelPos);
			return TRUE;
		}
		case WM_DESTROY:
			SaveWinRelPosition(_hParent,_hSelf,&WinRelPos);
			break;
		case WM_SIZE:
			AnchorResize(_hSelf,ShortcutAnchors,sizeof(ShortcutAnchors)/sizeof(CONTROL_ANCHOR));
			break;
		case WM_SIZING:
			return ClampMinWindowSize(&default_sm_size,wParam,(RECT*)lParam);
			break;
		case WM_NOTIFY: {
			NMHDR nmh = *((NMHDR*)lParam);
			if (nmh.hwndFrom == _hTabCtrl) {
				if (nmh.code == TCN_SELCHANGE) {
					int index = TabCtrl_GetCurSel(_hTabCtrl);
					switch (index) {
						case 0:
							_currentState = STATE_MENU;
							break;
						case 1:
							_currentState = STATE_MACRO;
							break;
						case 2:
							_currentState = STATE_USER;
							break;
						case 3:
							_currentState = STATE_PLUGIN;
							break;
						case 4:
							_currentState = STATE_SCINTILLA;
							break;
					}
					populateShortCuts();
				}
			}
			else if(nmh.hwndFrom==hlistview){
				switch(nmh.code){
					case NM_DBLCLK:
						return ::SendMessage(_hSelf, WM_COMMAND, IDC_SHORTCUT_MODIFY, LOWORD(lParam));
					case NM_RCLICK:
					{
						POINT p;
						::GetCursorPos(&p);
						if (!_rightClickMenu.isCreated())
						{
							vector<MenuItemUnit> itemUnitArray;
							itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_MODIFY, TEXT("Modify")));
							itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_DISABLE, TEXT("Disable")));
							itemUnitArray.push_back(MenuItemUnit(0, 0));
							itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_DELETE, TEXT("Delete")));
							_rightClickMenu.create(_hSelf, itemUnitArray);
						}
						switch(_currentState) {
							case STATE_MACRO:
							case STATE_USER: {
								_rightClickMenu.enableItem(IDC_SHORTCUT_DELETE, true);
								break; }
							case STATE_MENU:
							case STATE_PLUGIN:
							case STATE_SCINTILLA: {
								_rightClickMenu.enableItem(IDC_SHORTCUT_DELETE, false);
								break; }
						}
						
						_rightClickMenu.display(p);
						return TRUE;
					}
				}
			}
			break; }

		case WM_COMMAND : 
		{
			switch (LOWORD(wParam))
			{
				case IDCANCEL :
				{
					::EndDialog(_hSelf, -1);
					return TRUE;
				}
				case IDOK :
				{
					if(GetFocus()==hlistview)
						return ::SendMessage(_hSelf, WM_COMMAND, IDC_SHORTCUT_MODIFY, LOWORD(lParam));
					else
						::EndDialog(_hSelf, 0);
					return TRUE;
				}
				case IDC_SHORTCUT_FILTER2:
				case IDC_SHORTCUT_FILTER1:
					if(HIWORD(wParam)==EN_CHANGE)
						populateShortCuts();
					break;
				case IDC_SHORTCUT_DISABLE:
					{
						int sel=0;
						sel=disable_selected(FALSE);
						if(sel!=0){
							if(IDOK==MessageBox(_hSelf,TEXT("Ok to disable selected shortcuts?"),TEXT("Warning!"),MB_OKCANCEL|MB_SYSTEMMODAL)){
								disable_selected(TRUE);
								populateShortCuts();
							}
						}
					}
					break;
				case IDC_SHORTCUT_MODIFY :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					int index;
					int selected_row=getselectedrow();
					if(selected_row<0)
						break;
					index=getitemindex(selected_row);

					switch(_currentState) {
						case STATE_MENU: {
							//Get CommandShortcut corresponding to index
							vector<CommandShortcut> & shortcuts = nppParam->getUserShortcuts();
							CommandShortcut csc = shortcuts[index], prevcsc = shortcuts[index];
							csc.init(_hInst, _hSelf);
							csc.set_shortcut_info(_currentState,index);
							if (csc.doDialog() != -1 && prevcsc != csc) {	//shortcut was altered
								generic_string keys=csc.toString();
								nppParam->addUserModifiedIndex(index);
								shortcuts[index] = csc;
								ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str());
								update_col_width(keys.c_str(),2);
								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								TCHAR str[255];
								if(0<check_in_use(_currentState,index,&csc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR)))
									MessageBox(_hSelf,str,L"Duplicates found",MB_OK);
							}
							break; 
						}
						case STATE_MACRO: {
							//Get MacroShortcut corresponding to index
							vector<MacroShortcut> & shortcuts = nppParam->getMacroList();
							MacroShortcut msc = shortcuts[index], prevmsc = shortcuts[index];
							msc.init(_hInst, _hSelf);
							msc.set_shortcut_info(_currentState,index);
							if (msc.doDialog() != -1 && prevmsc != msc) {	//shortcut was altered
								generic_string name=msc.getName();
								generic_string keys=msc.toString();
								shortcuts[index] = msc;
								ListView_SetItemText(hlistview,selected_row,1,(LPWSTR)name.c_str());
								ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str());
								update_col_width(keys.c_str(),2);
								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								TCHAR str[255];
								if(0<check_in_use(_currentState,index,&msc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR)))
									MessageBox(_hSelf,str,L"Duplicates found",MB_OK);
							}
							break; 
						}
						case STATE_USER: {
							//Get UserCommand corresponding to index
							vector<UserCommand> & shortcuts = nppParam->getUserCommandList();
							UserCommand ucmd = shortcuts[index], prevucmd = shortcuts[index];
							ucmd.init(_hInst, _hSelf);
							ucmd.set_shortcut_info(_currentState,index);
							prevucmd = ucmd;
							if (ucmd.doDialog() != -1 && prevucmd != ucmd) {	//shortcut was altered
								generic_string name=ucmd.getName();
								generic_string keys=ucmd.toString();
								shortcuts[index] = ucmd;
								ListView_SetItemText(hlistview,selected_row,1,(LPWSTR)name.c_str());
								ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str());
								update_col_width(name.c_str(),1);
								update_col_width(keys.c_str(),2);
								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								TCHAR str[255];
								if(0<check_in_use(_currentState,index,&ucmd.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR)))
									MessageBox(_hSelf,str,L"Duplicates found",MB_OK);
							}
							break; 
						}
						case STATE_PLUGIN: {
							//Get PluginCmdShortcut corresponding to index
							vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList();
							if(shortcuts.empty())
								break;
							PluginCmdShortcut pcsc = shortcuts[index], prevpcsc = shortcuts[index];
							pcsc.init(_hInst, _hSelf);
							pcsc.set_shortcut_info(_currentState,index);
							prevpcsc = pcsc;
							if (pcsc.doDialog() != -1 && prevpcsc != pcsc) {	//shortcut was altered
								nppParam->addPluginModifiedIndex(index);
								generic_string keys=pcsc.toString();
								shortcuts[index] = pcsc;
								ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str());
								update_col_width(keys.c_str(),2);
								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								TCHAR str[255];
								if(0<check_in_use(_currentState,index,&pcsc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR)))
									MessageBox(_hSelf,str,L"Duplicates found",MB_OK);

								unsigned long cmdID = pcsc.getID();
								ShortcutKey shortcut;
								shortcut._isAlt = pcsc.getKeyCombo()._isAlt;
								shortcut._isCtrl = pcsc.getKeyCombo()._isCtrl;
								shortcut._isShift = pcsc.getKeyCombo()._isShift;
								shortcut._key = pcsc.getKeyCombo()._key;

								::SendMessage(_hParent, NPPM_INTERNAL_PLUGINSHORTCUTMOTIFIED, cmdID, (LPARAM)&shortcut);
							}
							break; 
						}
						case STATE_SCINTILLA: {
							//Get ScintillaKeyMap corresponding to index
							vector<ScintillaKeyMap> & shortcuts = nppParam->getScintillaKeyList();
							ScintillaKeyMap skm = shortcuts[index], prevskm = shortcuts[index];
							skm.init(_hInst, _hSelf);
							skm.set_shortcut_info(_currentState,index);
							if (skm.doDialog() != -1 && prevskm != skm) 
							{
								//shortcut was altered
								nppParam->addScintillaModifiedIndex(index);
								shortcuts[index] = skm;
								int i,max;
								TCHAR str[40]={0};
								max=skm.getSize();
								for(i=0;i<max;i++){
									generic_string keys=skm.toString(i);
									_sntprintf_s(str,sizeof(str)/sizeof(TCHAR),_TRUNCATE,L"%s%s%c",str,keys.c_str(),i<(max-1)?L';':L'');
								}
								ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)str);
								update_col_width(str,2);
								if(max>0){
									TCHAR str[255];
									KeyCombo skmkc=skm.getKeyComboByIndex(0);
									if(0<check_in_use(_currentState,index,&skmkc,nppParam,str,sizeof(str)/sizeof(TCHAR)))
										MessageBox(_hSelf,str,L"Duplicates found",MB_OK);
								}
								//Notify current Accelerator class to update key
								nppParam->getScintillaAccelerator()->updateKeys();
							}
							break; 
						}
					}
					return TRUE;
				}
				case IDC_SHORTCUT_DELETE :
				{
					NppParameters *nppParam = NppParameters::getInstance();
					int index,selected_row=getselectedrow();
					TCHAR str[255]={0},msg[255]={0};
					if(selected_row<0)
						break;
					index=getitemindex(selected_row);
					ListView_GetItemText(hlistview,selected_row,1,str,sizeof(str)/sizeof(TCHAR));
					_sntprintf_s(msg,sizeof(msg)/sizeof(TCHAR),_TRUNCATE,
						TEXT("%s\r\n%s"),
						TEXT("Are you sure you want to delete this shortcut?"),
						str);
					if (::MessageBox(_hSelf, msg, TEXT("Are you sure?"), MB_OKCANCEL) == IDOK)
					{
						int shortcutIndex = index;
						DWORD cmdID = 0;
						// Menu data
						size_t posBase = 0;
						size_t nbElem = 0;
						HMENU hMenu = NULL;
                        int modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN;
						switch(_currentState) 
						{
							case STATE_MENU:
							case STATE_PLUGIN:
							case STATE_SCINTILLA: 
							{
								return FALSE;			//this is bad
							}
							case STATE_MACRO: 
							{
								vector<MacroShortcut> & theMacros = nppParam->getMacroList();
								vector<MacroShortcut>::iterator it = theMacros.begin();
								cmdID = theMacros[shortcutIndex].getID();
								theMacros.erase(it + shortcutIndex);
								populateShortCuts();
								
								// preparing to remove from menu
								posBase = 6;
								nbElem = theMacros.size();
								hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_MACRO);
                                modifCmd = IDM_SETTING_SHORTCUT_MAPPER_MACRO;
								for (size_t i = shortcutIndex ; i < nbElem ; i++)	//lower the IDs of the remaining items so there are no gaps
								{
									MacroShortcut ms = theMacros[i];
									ms.setID(ms.getID() - 1);	//shift all IDs
									theMacros[i] = ms;
								}
								break; 
							}
							case STATE_USER: 
							{
								vector<UserCommand> & theUserCmds = nppParam->getUserCommandList();
								vector<UserCommand>::iterator it = theUserCmds.begin();
								cmdID = theUserCmds[shortcutIndex].getID();
								theUserCmds.erase(it + shortcutIndex);
								populateShortCuts();
							
								// preparing to remove from menu
								posBase = 2;
								nbElem = theUserCmds.size();
								hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_RUN);
                                modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN;
								for (size_t i = shortcutIndex ; i < nbElem ; i++)	//lower the IDs of the remaining items so there are no gaps
								{
									UserCommand uc = theUserCmds[i];
									uc.setID(uc.getID() - 1);	//shift all IDs
									theUserCmds[i] = uc;
								}
								break;
							}
						}

                        // updateShortcuts() will update all menu item - the menu items will be shifted
						nppParam->getAccelerator()->updateShortcuts();

                        // All menu items are shifted up. So we delete the last item
                        ::RemoveMenu(hMenu, posBase + nbElem, MF_BYPOSITION);

                        if (nbElem == 0) 
                        {
                            ::RemoveMenu(hMenu, modifCmd, MF_BYCOMMAND);
                            
                            //remove separator
							::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION);
                            ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION);
						}
					}
					return TRUE;
				}
			}
		}
		default:
			return FALSE;
	}
	return FALSE;
}