From e4cab506f85a8ab61169b3d7e271ce3add99f907 Mon Sep 17 00:00:00 2001 From: harrybharry Date: Fri, 6 Jun 2008 12:09:54 +0000 Subject: [PATCH] [Near 5.0] Change filehandling: buffers. This fixes many things like clonemode etc.. Faster shutdown. Open files with date pre-1970. Hide lines now saved during switches. Recent files has been redone: also numbers, more stable, no duplicates. Display asterisk in titlebar if dirty file is active. Some minor stuff that may have come along. git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository@215 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/src/Notepad_plus.cpp | 2662 ++++++++--------- PowerEditor/src/Notepad_plus.h | 217 +- PowerEditor/src/Notepad_plus.rc | 3 + PowerEditor/src/Parameters.cpp | 6 + .../src/ScitillaComponent/AutoCompletion.cpp | 6 +- PowerEditor/src/ScitillaComponent/Buffer.cpp | 501 +++- PowerEditor/src/ScitillaComponent/Buffer.h | 465 ++- .../src/ScitillaComponent/DocTabView.cpp | 230 +- .../src/ScitillaComponent/DocTabView.h | 41 +- .../src/ScitillaComponent/FindReplaceDlg.cpp | 25 +- .../src/ScitillaComponent/FindReplaceDlg.h | 18 +- PowerEditor/src/ScitillaComponent/Printer.cpp | 2 +- .../ScitillaComponent/ScintillaEditView.cpp | 525 ++-- .../src/ScitillaComponent/ScintillaEditView.h | 198 +- .../ScitillaComponent/UserDefineDialog.cpp | 28 +- PowerEditor/src/Utf8_16.h | 1 + PowerEditor/src/WinControls/TabBar/TabBar.cpp | 73 +- PowerEditor/src/WinControls/TabBar/TabBar.h | 14 +- .../src/WinControls/WindowsDlg/WindowsDlg.cpp | 89 +- .../src/WinControls/WindowsDlg/WindowsDlg.h | 8 +- PowerEditor/src/lastRecentFileList.cpp | 199 ++ PowerEditor/src/lastRecentFileList.h | 167 +- PowerEditor/src/menuCmdID.h | 3 + PowerEditor/src/resource.h | 4 +- PowerEditor/src/winmain.cpp | 14 +- .../visual.net/notepadPlus.vc.7.0.vcproj | 9 +- 26 files changed, 2885 insertions(+), 2623 deletions(-) create mode 100644 PowerEditor/src/lastRecentFileList.cpp diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 6d97b9e80..5ed1bad69 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -21,6 +21,8 @@ //#define INCLUDE_DEPRECATED_FEATURES 1 #include +//#include "dbghelp.h" + #include "Notepad_plus.h" #include "SysMsg.h" #include "FileDialog.h" @@ -46,23 +48,27 @@ enum tb_stat {tb_saved, tb_unsaved, tb_ro}; struct SortTaskListPred { - ScintillaEditView *_views[2]; + DocTabView *_views[2]; - SortTaskListPred(ScintillaEditView &p, ScintillaEditView &s) + SortTaskListPred(DocTabView &p, DocTabView &s) { _views[MAIN_VIEW] = &p; _views[SUB_VIEW] = &s; } bool operator()(const TaskLstFnStatus &l, const TaskLstFnStatus &r) const { - return _views[l._iView]->getBufferAt(l._docIndex).getRecentTag() > _views[r._iView]->getBufferAt(r._docIndex).getRecentTag(); + BufferID lID = _views[l._iView]->getBufferByIndex(l._docIndex); + BufferID rID = _views[r._iView]->getBufferByIndex(r._docIndex); + Buffer * bufL = MainFileManager->getBufferByID(lID); + Buffer * bufR = MainFileManager->getBufferByID(rID); + return bufL->getRecentTag() > bufR->getRecentTag(); } }; Notepad_plus::Notepad_plus(): Window(), _mainWindowStatus(0), _pDocTab(NULL), _pEditView(NULL), _pMainSplitter(NULL), _isfullScreen(false), _recordingMacro(false), _pTrayIco(NULL), _isUDDocked(false), _isRTL(false), - _linkTriggered(true), _isDocModifing(false), _isHotspotDblClicked(false), _isSaving(false), _sysMenuEntering(false), + _linkTriggered(true), _isDocModifing(false), _isHotspotDblClicked(false), _sysMenuEntering(false), _autoCompleteMain(&_mainEditView), _autoCompleteSub(&_subEditView) { @@ -167,6 +173,7 @@ Notepad_plus::Notepad_plus(): Window(), _mainWindowStatus(0), _pDocTab(NULL), _p Notepad_plus::~Notepad_plus() { (NppParameters::getInstance())->destroyInstance(); + MainFileManager->destroyInstance(); if (_pTrayIco) delete _pTrayIco; } @@ -250,57 +257,14 @@ void Notepad_plus::init(HINSTANCE hInst, HWND parent, const char *cmdLine, CmdLi if (cmdLine) { - char currPath[MAX_PATH]; - ::GetCurrentDirectory(sizeof currPath, currPath); - ::SetCurrentDirectory(currPath); - - LangType lt = cmdLineParams->_langType; - int ln = cmdLineParams->_line2go; - - if (PathFileExists(cmdLine)) - { - doOpen(cmdLine, cmdLineParams->_isReadOnly); - - if (lt != L_TXT) - _pEditView->setCurrentDocType(lt); - if (ln > 0) - _pEditView->execute(SCI_GOTOLINE, ln-1); - } - else - { - FileNameStringSplitter fnss(cmdLine); - char *pFn = NULL; - - for (int i = 0 ; i < fnss.size() ; i++) - { - pFn = (char *)fnss.getFileName(i); - doOpen((const char *)pFn, cmdLineParams->_isReadOnly); - - if (lt != L_TXT) - _pEditView->setCurrentDocType(lt); - if (ln > 0) - _pEditView->execute(SCI_GOTOLINE, ln-1); - } - } - // restore the doc type to L_TXT - //(NppParameters::getInstance())->setDefLang(L_TXT); - + loadCommandlineParams(cmdLine, cmdLineParams); } ::GetModuleFileName(NULL, _nppPath, MAX_PATH); - setTitleWith(_pEditView->getCurrentTitle()); - if (nppGUI._tabStatus & TAB_MULTILINE) ::SendMessage(_hSelf, WM_COMMAND, IDM_VIEW_DRAWTABBAR_MULTILINE, 0); - // Notify plugins that Notepad++ is ready - SCNotification scnN; - scnN.nmhdr.code = NPPN_READY; - scnN.nmhdr.hwndFrom = _hSelf; - scnN.nmhdr.idFrom = 0; - _pluginsManager.notify(&scnN); - if (!nppGUI._menuBarShow) ::SetMenu(_hSelf, NULL); @@ -309,6 +273,13 @@ void Notepad_plus::init(HINSTANCE hInst, HWND parent, const char *cmdLine, CmdLi { ::SendMessage(_hSelf, NPPM_HIDETABBAR, 0, TRUE); } + + // Notify plugins that Notepad++ is ready + SCNotification scnN; + scnN.nmhdr.code = NPPN_READY; + scnN.nmhdr.hwndFrom = _hSelf; + scnN.nmhdr.idFrom = 0; + _pluginsManager.notify(&scnN); } @@ -490,18 +461,26 @@ void Notepad_plus::saveDockingParams() bool Notepad_plus::loadSession(Session & session) { bool allSessionFilesLoaded = true; + BufferID lastOpened = BUFFER_INVALID; + int oldView = currentView(); + size_t i = 0; + switchEditViewTo(MAIN_VIEW); //open files in main for ( ; i < session.nbMainFiles() ; ) { const char *pFn = session._mainViewFiles[i]._fileName.c_str(); - if (PathFileExists(pFn)) + if (PathFileExists(pFn)) { + lastOpened = doOpen(pFn); + } else { + lastOpened = BUFFER_INVALID; + } + if (lastOpened != BUFFER_INVALID) { - doOpen(pFn); + showView(MAIN_VIEW); const char *pLn = session._mainViewFiles[i]._langName.c_str(); - setLangFromName(pLn); - _pEditView->getCurrentBuffer().setPosition(session._mainViewFiles[i]); - _pEditView->restoreCurrentPos(); + _mainEditView.getCurrentBuffer()->setPosition(session._mainViewFiles[i], &_mainEditView); + _mainEditView.restoreCurrentPos(); for (size_t j = 0 ; j < session._mainViewFiles[i].marks.size() ; j++) bookmarkAdd(session._mainViewFiles[i].marks[j]); @@ -516,33 +495,34 @@ bool Notepad_plus::loadSession(Session & session) } } - bool isSubViewOpened = false; - for (size_t k = 0 ; k < session.nbSubFiles() ; k++) + size_t k = 0; + switchEditViewTo(SUB_VIEW); //open files in sub + for ( ; k < session.nbSubFiles() ; ) { const char *pFn = session._subViewFiles[k]._fileName.c_str(); - if (PathFileExists(pFn)) + if (PathFileExists(pFn)) { + lastOpened = doOpen(pFn); + //check if already open in main. If so, clone + if (_mainDocTab.getIndexByBuffer(lastOpened) != -1) { + loadBufferIntoView(lastOpened, SUB_VIEW); + } + } else { + lastOpened = BUFFER_INVALID; + } + if (lastOpened != BUFFER_INVALID) { - if (doOpen(pFn) == OPEN_SUCCESS) - { - if (!isSubViewOpened) - { - docGotoAnotherEditView(MODE_TRANSFER); - isSubViewOpened = true; - } - } - else // switch back to Main view where this file is already opened - { - docGotoAnotherEditView(MODE_CLONE); - isSubViewOpened = true; - } + showView(SUB_VIEW); + if (canHideView(MAIN_VIEW)) + hideView(MAIN_VIEW); const char *pLn = session._subViewFiles[k]._langName.c_str(); - setLangFromName(pLn); - _pEditView->getCurrentBuffer().setPosition(session._subViewFiles[k]); - _pEditView->restoreCurrentPos(); + _subEditView.getCurrentBuffer()->setPosition(session._subViewFiles[k], &_subEditView); + _subEditView.restoreCurrentPos(); for (size_t j = 0 ; j < session._subViewFiles[k].marks.size() ; j++) bookmarkAdd(session._subViewFiles[k].marks[j]); + + k++; } else { @@ -551,11 +531,12 @@ bool Notepad_plus::loadSession(Session & session) allSessionFilesLoaded = false; } } + if (session._activeMainIndex < (size_t)_mainDocTab.nbItem())//session.nbMainFiles()) - _mainDocTab.activate(session._activeMainIndex); + activateBuffer(_mainDocTab.getBufferByIndex(session._activeMainIndex), MAIN_VIEW); if (session._activeSubIndex < (size_t)_subDocTab.nbItem())//session.nbSubFiles()) - _subDocTab.activate(session._activeSubIndex); + activateBuffer(_subDocTab.getBufferByIndex(session._activeSubIndex), SUB_VIEW); if ((session.nbSubFiles() > 0) && (session._activeView == MAIN_VIEW || session._activeView == SUB_VIEW)) switchEditViewTo(session._activeView); @@ -565,60 +546,18 @@ bool Notepad_plus::loadSession(Session & session) return allSessionFilesLoaded; } -bool Notepad_plus::doSimpleOpen(const char *fileName) -{ - Utf8_16_Read UnicodeConvertor; - - FILE *fp = fopen(fileName, "rb"); - - if (fp) - { - _pEditView->execute(SCI_CLEARALL, 0); - _pEditView->setCurrentTitle(fileName); - - char data[blockSize]; - - size_t lenFile = fread(data, 1, sizeof(data), fp); - bool isNotEmpty = (lenFile != 0); - - while (lenFile > 0) - { - lenFile = UnicodeConvertor.convert(data, lenFile); - _pEditView->execute(SCI_ADDTEXT, lenFile, reinterpret_cast(UnicodeConvertor.getNewBuf())); - lenFile = int(fread(data, 1, sizeof(data), fp)); - } - fclose(fp); - - UniMode unicodeMode = static_cast(UnicodeConvertor.getEncoding()); - (_pEditView->getCurrentBuffer()).setUnicodeMode(unicodeMode); - - if (unicodeMode != uni8Bit) - // Override the code page if Unicode - _pEditView->execute(SCI_SETCODEPAGE, SC_CP_UTF8); - - // Then replace the caret to the begining - _pEditView->execute(SCI_GOTOPOS, 0); - return true; - } - else - { - char msg[MAX_PATH + 100]; - strcpy(msg, "Can not open file \""); - strcat(msg, fileName); - strcat(msg, "\"."); - ::MessageBox(_hSelf, msg, "Open File error", MB_OK); - return false; - } -} - - -int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) +BufferID Notepad_plus::doOpen(const char *fileName, bool isReadOnly) { char longFileName[MAX_PATH]; ::GetFullPathName(fileName, MAX_PATH, longFileName, NULL); - if (switchToFile(longFileName)) + _lastRecentFileList.remove(longFileName); + + BufferID test = MainFileManager->getBufferFromName(longFileName); + if (test != BUFFER_INVALID) { + //switchToFile(test); + //Dont switch, not responsibility of doOpen, but of caller if (_pTrayIco) { if (_pTrayIco->isInTray()) @@ -628,7 +567,7 @@ int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) ::SendMessage(_hSelf, WM_SIZE, 0, 0); } } - return OPEN_EXISTS; + return test; } if (!PathFileExists(longFileName)) @@ -645,48 +584,33 @@ int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) if (::MessageBox(_hSelf, str2display, "Create new file", MB_YESNO) == IDYES) { - FILE *f = fopen(longFileName, "w"); - fclose(f); + bool res = MainFileManager->createEmptyFile(longFileName); + if (!res) { + sprintf(str2display, "Cannot create the file \"%s\"", longFileName); + ::MessageBox(_hSelf, str2display, "Create new file", MB_OK); + return BUFFER_INVALID; + } } else { - _lastRecentFileList.remove(longFileName); - return OPEN_FAILURE; + return BUFFER_INVALID; } } else { - _lastRecentFileList.remove(longFileName); - return OPEN_FAILURE; + return BUFFER_INVALID; } } - // if file2open matches the ext of user defined session file ext, then it'll be opened as a session - const char *definedSessionExt = NppParameters::getInstance()->getNppGUI()._definedSessionExt.c_str(); - if (*definedSessionExt != '\0') - { - char fncp[MAX_PATH]; - strcpy(fncp, longFileName); - char *pExt = PathFindExtension(fncp); - string usrSessionExt = ""; - if (*definedSessionExt != '.') - { - usrSessionExt += "."; - } - usrSessionExt += definedSessionExt; - if (!strcmp(pExt, usrSessionExt.c_str())) - { - return fileLoadSession(longFileName); - } - } - Utf8_16_Read UnicodeConvertor; - - bool isNewDoc2Close = false; - FILE *fp = fopen(longFileName, "rb"); - - if (fp) + BufferID buffer = MainFileManager->loadFile(longFileName); + if (buffer != BUFFER_INVALID) { + Buffer * buf = MainFileManager->getBufferByID(buffer); + // if file is read only, we set the view read only + if (isReadOnly) + buf->setUserReadOnly(true); + // Notify plugins that current file is just opened SCNotification scnN; scnN.nmhdr.code = NPPN_FILEBEFOREOPEN; @@ -694,75 +618,8 @@ int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) scnN.nmhdr.idFrom = 0; _pluginsManager.notify(&scnN); - if ((_pEditView->getNbDoc() == 1) - && Buffer::isUntitled(_pEditView->getCurrentTitle()) - && (!_pEditView->isCurrentDocDirty()) && (_pEditView->getCurrentDocLen() == 0)) - { - isNewDoc2Close = true; - } - setTitleWith(_pDocTab->newDoc(longFileName)); + loadBufferIntoView(buffer, currentView()); - // It's VERY IMPORTANT to reset the view - _pEditView->execute(SCI_CLEARALL); - _pEditView->execute(SCI_SETUNDOCOLLECTION, false); - - char data[blockSize]; - size_t lenFile = fread(data, 1, sizeof(data), fp); - bool isNotEmpty = (lenFile != 0); - - //try { - while (lenFile > 0) - { - lenFile = UnicodeConvertor.convert(data, lenFile); - _pEditView->execute(SCI_ADDTEXT, lenFile, reinterpret_cast(UnicodeConvertor.getNewBuf())); - lenFile = int(fread(data, 1, sizeof(data), fp)); - } - /*} - catch (...) - { - ::MessageBox(_hSelf, "File is too large to open.", "Open File Error", MB_OK); - }*/ - fclose(fp); - - // 3 formats : WIN_FORMAT, UNIX_FORMAT and MAC_FORMAT - (_pEditView->getCurrentBuffer()).determinateFormat(isNotEmpty?UnicodeConvertor.getNewBuf():(char *)("")); - _pEditView->execute(SCI_SETEOLMODE, _pEditView->getCurrentBuffer().getFormat()); - - // detect if it's a binary file (non ascii file) - //(_pEditView->getCurrentBuffer()).detectBin(isNotEmpty?UnicodeConvertor.getNewBuf():(char *)("")); - - UniMode unicodeMode = static_cast(UnicodeConvertor.getEncoding()); - (_pEditView->getCurrentBuffer()).setUnicodeMode(unicodeMode); - - if (unicodeMode != uni8Bit) - // Override the code page if Unicode - _pEditView->execute(SCI_SETCODEPAGE, SC_CP_UTF8); - - if (isReadOnly) - (_pEditView->getCurrentBuffer()).setReadOnly(true); - - _pEditView->getFocus(); - _pEditView->execute(SCI_SETUNDOCOLLECTION, true); - _pEditView->execute(SCI_SETSAVEPOINT); - _pEditView->execute(SCI_EMPTYUNDOBUFFER); - - // if file is read only, we set the view read only - _pEditView->execute(SCI_SETREADONLY, _pEditView->isCurrentBufReadOnly()); - if (isNewDoc2Close) - _pDocTab->closeDocAt(0); - - int numLines = int(_pEditView->execute(SCI_GETLINECOUNT)); - - char numLineStr[32]; - itoa(numLines, numLineStr, 10); - int nbDigit = strlen(numLineStr); - - if (_pEditView->increaseMaxNbDigit(nbDigit)) - _pEditView->setLineNumberWidth(_pEditView->hasMarginShowed(ScintillaEditView::_SC_MARGE_LINENUMBER)); - - // Then replace the caret to the begining - _pEditView->execute(SCI_GOTOPOS, 0); - _lastRecentFileList.remove(longFileName); if (_pTrayIco) { if (_pTrayIco->isInTray()) @@ -775,13 +632,13 @@ int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) PathRemoveFileSpec(longFileName); _linkTriggered = true; _isDocModifing = false; - setWorkingDir(longFileName); - + + _pEditView->getFocus(); //needed? // Notify plugins that current file is just opened scnN.nmhdr.code = NPPN_FILEOPENED; _pluginsManager.notify(&scnN); - return OPEN_SUCCESS; + return buffer; } else { @@ -791,24 +648,87 @@ int Notepad_plus::doOpen(const char *fileName, bool isReadOnly) strcat(msg, longFileName); strcat(msg, "\"."); ::MessageBox(_hSelf, msg, "ERR", MB_OK); - _lastRecentFileList.remove(longFileName); - return OPEN_FAILURE; + return BUFFER_INVALID; } } +bool Notepad_plus::doReload(BufferID id, bool alert) +{ + if (!switchToFile(id)) //test if file present + { + return false; + } + if (alert) + { + if (::MessageBox(_hSelf, "Do you want to reload the current file?", "Reload", MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL) != IDYES) + return false; + } + return MainFileManager->reloadBuffer(id); +} + +bool Notepad_plus::doSave(BufferID id, const char * filename, bool isCopy) +{ + SCNotification scnN; + // Notify plugins that current file is about to be saved + if (!isCopy) + { + + scnN.nmhdr.code = NPPN_FILEBEFORESAVE; + scnN.nmhdr.hwndFrom = _hSelf; + scnN.nmhdr.idFrom = 0; + _pluginsManager.notify(&scnN); + } + + bool res = MainFileManager->saveBuffer(id, filename, isCopy); + + if (!isCopy) + { + scnN.nmhdr.code = NPPN_FILESAVED; + _pluginsManager.notify(&scnN); + } + + if (!res) + ::MessageBox(_hSelf, "Please check whether if this file is opened in another program", "Save failed", MB_OK); + return res; +} + +void Notepad_plus::doClose(BufferID id, int whichOne) { + Buffer * buf = MainFileManager->getBufferByID(id); + + // Notify plugins that current file is about to be closed + SCNotification scnN; + scnN.nmhdr.code = NPPN_FILEBEFORECLOSE; + scnN.nmhdr.hwndFrom = _hSelf; + scnN.nmhdr.idFrom = 0; + _pluginsManager.notify(&scnN); + + //add to recent files if its an existing file + if (!buf->isUntitled()) + { + _lastRecentFileList.add(buf->getFilePath()); + } + + //Do all the works + removeBufferFromView(id, whichOne); + + // Notify plugins that current file is closed + scnN.nmhdr.code = NPPN_FILECLOSED; + _pluginsManager.notify(&scnN); + + return; +} void Notepad_plus::fileNew() { - setTitleWith(_pDocTab->newDoc(NULL)); - setWorkingDir(NULL); + BufferID newBufID = MainFileManager->newEmptyDocument(); + loadBufferIntoView(newBufID, currentView(), true); //true, because we want multiple new files if possible + activateBuffer(newBufID, currentView()); } bool Notepad_plus::fileReload() { - const char * fn = _pEditView->getCurrentTitle(); - if (Buffer::isUntitled(fn)) return false; - if (::MessageBox(_hSelf, "Do you want to reload the current file?", "Reload", MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL) == IDYES) - reload(fn); - return true; + BufferID buf = _pEditView->getCurrentBufferID(); + return doReload(buf, true); } + string exts2Filters(string exts) { const char *extStr = exts.c_str(); char aExt[MAX_PATH]; @@ -865,7 +785,7 @@ void Notepad_plus::setFileOpenSaveDlgFilters(FileDialog & fDlg) int i = 0; Lang *l = NppParameters::getInstance()->getLangFromIndex(i++); - LangType curl = _pEditView->getCurrentBuffer().getLangType(); + LangType curl = _pEditView->getCurrentBuffer()->getLangType(); while (l) { @@ -921,119 +841,60 @@ void Notepad_plus::fileOpen() setFileOpenSaveDlgFilters(fDlg); + BufferID lastOpened = BUFFER_INVALID; if (stringVector *pfns = fDlg.doOpenMultiFilesDlg()) { - int sz = int(pfns->size()); - for (int i = 0 ; i < sz ; i++) - doOpen((pfns->at(i)).c_str(), fDlg.isReadOnly()); + size_t sz = pfns->size(); + for (size_t i = 0 ; i < sz ; i++) { + if (isFileSession(pfns->at(i).c_str())) { + fileLoadSession(pfns->at(i).c_str()); + lastOpened = BUFFER_INVALID; + } else { + BufferID test = doOpen(pfns->at(i).c_str(), fDlg.isReadOnly()); + if (test != BUFFER_INVALID) + lastOpened = test; + } + } + } + if (lastOpened != BUFFER_INVALID) { + switchToFile(lastOpened); } } - - -bool Notepad_plus::doReload(const char *fileName, bool alert) -{ - char longFileName[MAX_PATH] =""; - ::GetFullPathName(fileName, MAX_PATH, longFileName, NULL); - - if (switchToFile(longFileName)) +bool Notepad_plus::isFileSession(const char * filename) { + // if file2open matches the ext of user defined session file ext, then it'll be opened as a session + const char *definedSessionExt = NppParameters::getInstance()->getNppGUI()._definedSessionExt.c_str(); + if (*definedSessionExt != '\0') { - if (alert) + char fncp[MAX_PATH]; + strcpy(fncp, filename); + char *pExt = PathFindExtension(fncp); + string usrSessionExt = ""; + if (*definedSessionExt != '.') { - if (::MessageBox(_hSelf, "Do you want to reload the current file?", "Reload", MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL) == IDYES) - reload(longFileName); + usrSessionExt += "."; } - else - reload(longFileName); + usrSessionExt += definedSessionExt; - return true; + if (!stricmp(pExt, usrSessionExt.c_str())) + { + return true; + } } return false; } -bool Notepad_plus::doSave(const char *filename, UniMode mode, bool isCopy) +bool Notepad_plus::fileSave(BufferID id) { - bool isHidden = false; - bool isSys = false; - DWORD attrib; + BufferID bufferID = id; + if (id == BUFFER_INVALID) + bufferID = _pEditView->getCurrentBufferID(); + Buffer * buf = MainFileManager->getBufferByID(bufferID); - if (PathFileExists(filename)) + if (!buf->getFileReadOnly() && buf->isDirty()) //cannot save if readonly { - attrib = ::GetFileAttributes(filename); - - if (attrib != INVALID_FILE_ATTRIBUTES) - { - isHidden = (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; - if (isHidden) - ::SetFileAttributes(filename, attrib & ~FILE_ATTRIBUTE_HIDDEN); - - isSys = (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; - if (isSys) - ::SetFileAttributes(filename, attrib & ~FILE_ATTRIBUTE_SYSTEM); - - } - } - - if (mode == uniCookie) - mode = uni8Bit; - - Utf8_16_Write UnicodeConvertor; - if (_pEditView->execute(SCI_GETCODEPAGE) != 0) - UnicodeConvertor.setEncoding(static_cast(mode)); - - FILE *fp = UnicodeConvertor.fopen(filename, "wb"); - - if (fp) - { - SCNotification scnN; - // Notify plugins that current file is about to be saved - if (!isCopy) - { - - scnN.nmhdr.code = NPPN_FILEBEFORESAVE; - scnN.nmhdr.hwndFrom = _hSelf; - scnN.nmhdr.idFrom = 0; - _pluginsManager.notify(&scnN); - } - char data[blockSize + 1]; - int lengthDoc = _pEditView->getCurrentDocLen(); - for (int i = 0; i < lengthDoc; i += blockSize) - { - int grabSize = lengthDoc - i; - if (grabSize > blockSize) - grabSize = blockSize; - - _pEditView->getText(data, i, i + grabSize); - UnicodeConvertor.fwrite(data, grabSize); - } - UnicodeConvertor.fclose(); - - if (isHidden) - ::SetFileAttributes(filename, attrib | FILE_ATTRIBUTE_HIDDEN); - - if (isSys) - ::SetFileAttributes(filename, attrib | FILE_ATTRIBUTE_SYSTEM); - - if (!isCopy) - { - _pEditView->updateCurrentBufTimeStamp(); - _pEditView->execute(SCI_SETSAVEPOINT); - - scnN.nmhdr.code = NPPN_FILESAVED; - _pluginsManager.notify(&scnN); - } - return true; - } - ::MessageBox(_hSelf, "Please check whether if this file is opened in another program", "Save failed", MB_OK); - return false; -} - -bool Notepad_plus::fileSave() -{ - if (_pEditView->isCurrentDocDirty()) - { - const char *fn = _pEditView->getCurrentTitle(); - if (Buffer::isUntitled(fn)) + const char *fn = buf->getFilePath(); + if (buf->isUntitled()) { return fileSaveAs(); } @@ -1109,81 +970,261 @@ bool Notepad_plus::fileSave() ::CopyFile(fn, fn_dateTime_bak.c_str(), FALSE); } - return doSave(fn, _pEditView->getCurrentBuffer().getUnicodeMode()); + return doSave(bufferID, buf->getFilePath(), false); } } return false; } bool Notepad_plus::fileSaveAll() { - - int iCurrent = _pEditView->getCurrentDocIndex(); - - if (_mainWindowStatus & TWO_VIEWS_MASK) - { - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - int iCur = _pEditView->getCurrentDocIndex(); - - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) - { - _pDocTab->activate(i); - if (!_pEditView->getCurrentBuffer().isReadOnly()) - fileSave(); - } - - _pDocTab->activate(iCur); - - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - } - - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) - { - _pDocTab->activate(i); - if (!_pEditView->getCurrentBuffer().isReadOnly()) - fileSave(); + if (viewVisible(MAIN_VIEW)) { + for(int i = 0; i < _mainDocTab.nbItem(); i++) { + BufferID idToSave = _mainDocTab.getBufferByIndex(i); + fileSave(idToSave); + } } - _pDocTab->activate(iCurrent); + if (viewVisible(SUB_VIEW)) { + for(int i = 0; i < _subDocTab.nbItem(); i++) { + BufferID idToSave = _subDocTab.getBufferByIndex(i); + fileSave(idToSave); + } + } + return true; +} + +bool Notepad_plus::fileSaveAs(BufferID id, bool isSaveCopy) +{ + BufferID bufferID = id; + if (id == BUFFER_INVALID) + bufferID = _pEditView->getCurrentBufferID(); + Buffer * buf = MainFileManager->getBufferByID(bufferID); + + FileDialog fDlg(_hSelf, _hInst); + + fDlg.setExtFilter("All types", ".*", NULL); + setFileOpenSaveDlgFilters(fDlg); + + fDlg.setDefFileName(buf->getFileName()); + char *pfn = fDlg.doSaveDlg(); + + if (pfn) + { + BufferID other = _pNonDocTab->findBufferByName(pfn); + if (other == BUFFER_INVALID) //can save, other view doesnt contain buffer + { + doSave(bufferID, pfn, isSaveCopy); + return true; + } + else //cannot save, other view has buffer already open, activate it + { + ::MessageBox(_hSelf, "The file is already opened in the Notepad++.", "ERROR", MB_OK | MB_ICONSTOP); + switchToFile(other); + return false; + } + } + else // cancel button is pressed + { + checkModifiedDocument(); + return false; + } +} + +bool Notepad_plus::fileClose(BufferID id, int curView) +{ + BufferID bufferID = id; + if (id == BUFFER_INVALID) + bufferID = _pEditView->getCurrentBufferID(); + Buffer * buf = MainFileManager->getBufferByID(bufferID); + + int res; + + //process the fileNamePath into LRF + const char *fileNamePath = buf->getFilePath(); + + if (buf->isDirty()) + { + res = doSaveOrNot(fileNamePath); + if (res == IDYES) + { + if (!fileSave(id)) // the cancel button of savedialog is pressed, aborts closing + return false; + } + else if (res == IDCANCEL) + { + return false; //cancel aborts closing + } + else + { + // else IDNO we continue + } + } + + int viewToClose = currentView(); + if (curView != -1) + viewToClose = curView; + //first check amount of documents, we dont want the view to hide if we closed a secondary doc with primary being empty + int nrDocs = _pDocTab->nbItem(); + doClose(bufferID, viewToClose); + if (nrDocs == 1 && canHideView(currentView())) { //close the view if both visible + hideView(viewToClose); + } + + return true; +} + +bool Notepad_plus::fileCloseAll() +{ + //closes all documents, makes the current view the only one visible + + //first check if we need to save any file + for(int i = 0; i < _mainDocTab.nbItem(); i++) { + BufferID id = _mainDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(id); + if (buf->isDirty()) { + int res = doSaveOrNot(buf->getFilePath()); + if (res == IDYES) { + if (!fileSave(id)) + return false; //abort entire procedure + } else if (res == IDCANCEL) { + return false; + //otherwise continue (IDNO) + } + } + } + for(int i = 0; i < _subDocTab.nbItem(); i++) { + BufferID id = _subDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(id); + if (buf->isDirty()) { + int res = doSaveOrNot(buf->getFilePath()); + if (res == IDYES) { + if (!fileSave(id)) + return false; //abort entire procedure + else if (res == IDCANCEL) + return false; + //otherwise continue (IDNO) + } + } + } + + //Then start closing, inactive view first so the active is left open + if (bothActive()) + { //first close all docs in non-current view, which gets closed automatically + //Set active tab to the last one closed. + activateBuffer(_pNonDocTab->getBufferByIndex(0), otherView()); + for(int i = _pNonDocTab->nbItem() - 1; i >= 0; i--) { //close all from right to left + doClose(_pNonDocTab->getBufferByIndex(i), otherView()); + } + hideView(otherView()); + } + + activateBuffer(_pDocTab->getBufferByIndex(0), currentView()); + for(int i = _pDocTab->nbItem() - 1; i >= 0; i--) { //close all from right to left + doClose(_pDocTab->getBufferByIndex(i), currentView()); + } + return true; +} + +bool Notepad_plus::fileCloseAllButCurrent() +{ + BufferID current = _pEditView->getCurrentBufferID(); + int active = _pDocTab->getCurrentTabIndex(); + //closes all documents, makes the current view the only one visible + + //first check if we need to save any file + for(int i = 0; i < _mainDocTab.nbItem(); i++) { + BufferID id = _mainDocTab.getBufferByIndex(i); + if (id == current) + continue; + Buffer * buf = MainFileManager->getBufferByID(id); + if (buf->isDirty()) { + int res = doSaveOrNot(buf->getFilePath()); + if (res == IDYES) { + if (!fileSave(id)) + return false; //abort entire procedure + } else if (res == IDCANCEL) { + return false; + //otherwise continue (IDNO) + } + } + } + for(int i = 0; i < _subDocTab.nbItem(); i++) { + BufferID id = _subDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(id); + if (id == current) + continue; + if (buf->isDirty()) { + int res = doSaveOrNot(buf->getFilePath()); + if (res == IDYES) { + if (!fileSave(id)) + return false; //abort entire procedure + else if (res == IDCANCEL) + return false; + //otherwise continue (IDNO) + } + } + } + + //Then start closing, inactive view first so the active is left open + if (bothActive()) + { //first close all docs in non-current view, which gets closed automatically + //Set active tab to the last one closed. + activateBuffer(_pNonDocTab->getBufferByIndex(0), otherView()); + for(int i = _pNonDocTab->nbItem() - 1; i >= 0; i--) { //close all from right to left + doClose(_pNonDocTab->getBufferByIndex(i), otherView()); + } + hideView(otherView()); + } + + activateBuffer(_pDocTab->getBufferByIndex(0), currentView()); + for(int i = _pDocTab->nbItem() - 1; i >= 0; i--) { //close all from right to left + if (i == active) { //dont close active index + continue; + } + doClose(_pDocTab->getBufferByIndex(i), currentView()); + } return true; } bool Notepad_plus::replaceAllFiles() { - int iCurrent = _pEditView->getCurrentDocIndex(); + BufferID active = _mainEditView.getCurrentBufferID(); + ScintillaEditView * pOldView = _pEditView; + _pEditView = &_mainEditView; + int nbTotal = 0; const bool isEntireDoc = true; - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (_mainWindowStatus & WindowMainActive) { - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - int iCur = _pEditView->getCurrentDocIndex(); - - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) + for (int i = 0 ; i < _mainDocTab.nbItem() ; i++) { - _pDocTab->activate(i); - if (!_pEditView->getCurrentBuffer().isReadOnly()) - { - _pEditView->execute(SCI_BEGINUNDOACTION); + _mainEditView.activateBuffer(_mainDocTab.getBufferByIndex(i)); + if (!_mainEditView.getCurrentBuffer()->isReadOnly()) { + _mainEditView.execute(SCI_BEGINUNDOACTION); nbTotal += _findReplaceDlg.processAll(ProcessReplaceAll, NULL, NULL, isEntireDoc, NULL); - _pEditView->execute(SCI_ENDUNDOACTION); + _mainEditView.execute(SCI_ENDUNDOACTION); } + } - _pDocTab->activate(iCur); - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); } - - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) - { - _pDocTab->activate(i); - if (!_pEditView->getCurrentBuffer().isReadOnly()) - { - _pEditView->execute(SCI_BEGINUNDOACTION); - nbTotal += _findReplaceDlg.processAll(ProcessReplaceAll, NULL, NULL, isEntireDoc, NULL); - _pEditView->execute(SCI_ENDUNDOACTION); - } - } - _pDocTab->activate(iCurrent); + if (_mainWindowStatus & WindowSubActive) + { + for (int i = 0 ; i < _subDocTab.nbItem() ; i++) + { + _mainEditView.activateBuffer(_mainDocTab.getBufferByIndex(i)); + if (!_mainEditView.getCurrentBuffer()->isReadOnly()) { + _mainEditView.execute(SCI_BEGINUNDOACTION); + nbTotal += _findReplaceDlg.processAll(ProcessReplaceAll, NULL, NULL, isEntireDoc, NULL); + _mainEditView.execute(SCI_ENDUNDOACTION); + } + + } + } + + _mainEditView.activateBuffer(active); + _pEditView = pOldView; char result[64]; if (nbTotal < 0) @@ -1328,10 +1369,7 @@ void Notepad_plus::getMatchedFileNames(const char *dir, const vector & p bool Notepad_plus::findInFiles(bool isRecursive, bool isInHiddenDir) { int nbTotal = 0; - ScintillaEditView *pOldView = _pEditView; - - _pEditView = &_invisibleEditView; - _findReplaceDlg.setFinderReadOnly(false); + BufferID oldBufID = _pEditView->getCurrentBufferID(); if (!_findReplaceDlg.isFinderEmpty()) _findReplaceDlg.clearFinder(); @@ -1351,117 +1389,65 @@ bool Notepad_plus::findInFiles(bool isRecursive, bool isInHiddenDir) for (size_t i = 0 ; i < fileNames.size() ; i++) { - const char *fn = fileNames[i].c_str(); - if (doSimpleOpen(fn)) - nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, true, fn); + BufferID id = MainFileManager->loadFile(fileNames.at(i).c_str()); + if (id != BUFFER_INVALID) { + MainFileManager->addBufferReference(id, _pEditView); + _pEditView->activateBuffer(id); + nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, true, fileNames.at(i).c_str()); + _pEditView->activateBuffer(oldBufID); + MainFileManager->closeBuffer(id, _pEditView); + } } - _findReplaceDlg.setFinderReadOnly(); - _findReplaceDlg.putFindResult(nbTotal); - _pEditView = pOldView; + _findReplaceDlg.putFindResult(nbTotal); return true; } bool Notepad_plus::findInOpenedFiles() { - int iCurrent = _pEditView->getCurrentDocIndex(); + BufferID mainID = _mainEditView.getCurrentBufferID(); + ScintillaEditView * pOldView = _pEditView; + _pEditView = &_mainEditView; + int nbTotal = 0; const bool isEntireDoc = true; - _findReplaceDlg.setFinderReadOnly(false); - //_findReplaceDlg.setFinderStyle(); - //_pFinder->defineDocType(L_TXT); - //_pFinder->execute(SCI_STYLESETSIZE, STYLE_DEFAULT, 8); - if (!_findReplaceDlg.isFinderEmpty()) _findReplaceDlg.clearFinder(); _findReplaceDlg.setSearchWord2Finder(); - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (_mainWindowStatus & WindowMainActive) { - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - int iCur = _pEditView->getCurrentDocIndex(); - - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) + for (int i = 0 ; i < _mainDocTab.nbItem() ; i++) { - _pDocTab->activate(i); - - _pEditView->execute(SCI_BEGINUNDOACTION); - nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, isEntireDoc, _pEditView->getCurrentTitle()); - _pEditView->execute(SCI_ENDUNDOACTION); + _mainEditView.activateBuffer(_mainDocTab.getBufferByIndex(i)); + _mainEditView.execute(SCI_BEGINUNDOACTION); + nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, isEntireDoc, _pEditView->getCurrentBuffer()->getFilePath()); + _mainEditView.execute(SCI_ENDUNDOACTION); } - _pDocTab->activate(iCur); - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); } - for (size_t i = 0 ; i < _pEditView->getNbDoc() ; i++) - { - _pDocTab->activate(i); - - _pEditView->execute(SCI_BEGINUNDOACTION); - nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, isEntireDoc, _pEditView->getCurrentTitle()); - _pEditView->execute(SCI_ENDUNDOACTION); - } + if (_mainWindowStatus & WindowSubActive) + { + for (int i = 0 ; i < _subDocTab.nbItem() ; i++) + { + _mainEditView.activateBuffer(_mainDocTab.getBufferByIndex(i)); + _mainEditView.execute(SCI_BEGINUNDOACTION); + nbTotal += _findReplaceDlg.processAll(ProcessFindAll, NULL, NULL, isEntireDoc, _pEditView->getCurrentBuffer()->getFilePath()); + _mainEditView.execute(SCI_ENDUNDOACTION); + + } + } + _mainEditView.activateBuffer(mainID); - _pDocTab->activate(iCurrent); - - _findReplaceDlg.setFinderReadOnly(); + _pEditView = pOldView; _findReplaceDlg.putFindResult(nbTotal); - return true; } -bool Notepad_plus::fileSaveAs(bool isSaveCopy) -{ - FileDialog fDlg(_hSelf, _hInst); - - fDlg.setExtFilter("All types", ".*", NULL); - setFileOpenSaveDlgFilters(fDlg); - - char str[MAX_PATH]; - strcpy(str, _pEditView->getCurrentTitle()); - - fDlg.setDefFileName(PathFindFileName(str)); - - int currentDocIndex = _pEditView->getCurrentDocIndex(); - _isSaving = true; - char *pfn = fDlg.doSaveDlg(); - _isSaving = false; - if (pfn) - { - int i = _pEditView->findDocIndexByName(pfn); - if ((i == -1) || (i == currentDocIndex)) - { - doSave(pfn, _pEditView->getCurrentBuffer().getUnicodeMode(), isSaveCopy); - if (!isSaveCopy) - { - _pEditView->setCurrentTitle(pfn); - _pEditView->setCurrentDocReadOnly(false); - _pDocTab->updateCurrentTabItem(PathFindFileName(pfn)); - setTitleWith(pfn); - setLangStatus(_pEditView->getCurrentDocType()); - checkLangsMenu(-1); - } - return true; - } - else - { - ::MessageBox(_hSelf, "The file is already opened in the Notepad++.", "ERROR", MB_OK | MB_ICONSTOP); - _pDocTab->activate(i); - return false; - } - checkModifiedDocument(); - } - else // cancel button is pressed - { - checkModifiedDocument(); - return false; - } -} - void Notepad_plus::filePrint(bool showDialog) { Printer printer; @@ -1503,13 +1489,23 @@ void Notepad_plus::checkClipboard() void Notepad_plus::checkDocState() { - bool isCurrentDirty = _pEditView->isCurrentDocDirty(); - bool isSeveralDirty = (!_pEditView->isAllDocsClean()) || (!getNonCurrentEditView()->isAllDocsClean()); + Buffer * curBuf = _pEditView->getCurrentBuffer(); + + bool isCurrentDirty = curBuf->isDirty(); + bool isSeveralDirty = isCurrentDirty; + if (!isCurrentDirty) { + for(int i = 0; i < MainFileManager->getNrBuffers(); i++) { + if (MainFileManager->getBufferByIndex(i)->isDirty()) { + isSeveralDirty = true; + break; + } + } + } enableCommand(IDM_FILE_SAVE, isCurrentDirty, MENU | TOOLBAR); enableCommand(IDM_FILE_SAVEALL, isSeveralDirty, MENU | TOOLBAR); - bool isSysReadOnly = _pEditView->isCurrentBufSysReadOnly(); + bool isSysReadOnly = curBuf->getFileReadOnly(); if (isSysReadOnly) { ::CheckMenuItem(_mainMenuHandle, IDM_EDIT_SETREADONLY, MF_BYCOMMAND | MF_UNCHECKED); @@ -1520,12 +1516,12 @@ void Notepad_plus::checkDocState() { enableCommand(IDM_EDIT_SETREADONLY, true, MENU); enableCommand(IDM_EDIT_CLEARREADONLY, false, MENU); - bool isUserReadOnly = _pEditView->isCurrentBufUserReadOnly(); + bool isUserReadOnly = curBuf->getUserReadOnly(); ::CheckMenuItem(_mainMenuHandle, IDM_EDIT_SETREADONLY, MF_BYCOMMAND | (isUserReadOnly?MF_CHECKED:MF_UNCHECKED)); } - enableConvertMenuItems((_pEditView->getCurrentBuffer()).getFormat()); - checkUnicodeMenuItems((_pEditView->getCurrentBuffer()).getUnicodeMode()); + enableConvertMenuItems(curBuf->getFormat()); + checkUnicodeMenuItems(curBuf->getUnicodeMode()); checkLangsMenu(-1); } @@ -1547,7 +1543,7 @@ void Notepad_plus::checkMacroState() void Notepad_plus::checkSyncState() { - bool canDoSync = _mainDocTab.isVisible() && _subDocTab.isVisible(); + bool canDoSync = viewVisible(MAIN_VIEW) && viewVisible(SUB_VIEW); if (!canDoSync) { _syncInfo._isSynScollV = false; @@ -1561,32 +1557,17 @@ void Notepad_plus::checkSyncState() enableCommand(IDM_VIEW_SYNSCROLLH, canDoSync, MENU | TOOLBAR); } -void Notepad_plus::synchronise() -{ - Buffer & bufSrc = _pEditView->getCurrentBuffer(); - - const char *fn = bufSrc.getFileName(); - - int i = getNonCurrentDocTab()->find(fn); - if (i != -1) - { - Buffer & bufDest = getNonCurrentEditView()->getBufferAt(i); - bufDest.synchroniseWith(bufSrc); - getNonCurrentDocTab()->updateTabItem(i); - } -} - - void Notepad_plus::checkLangsMenu(int id) const { + Buffer * curBuf = _pEditView->getCurrentBuffer(); if (id == -1) { - id = (NppParameters::getInstance())->langTypeToCommandID(_pEditView->getCurrentDocType()); + id = (NppParameters::getInstance())->langTypeToCommandID(curBuf->getLangType()); if (id == IDM_LANG_USER) { - if (_pEditView->getCurrentBuffer().isUserDefineLangExt()) + if (curBuf->isUserDefineLangExt()) { - const char *userLangName = _pEditView->getCurrentBuffer().getUserDefineLangName(); + const char *userLangName = curBuf->getUserDefineLangName(); char menuLangName[16]; for (int i = IDM_LANG_USER + 1 ; i <= IDM_LANG_USER_LIMIT ; i++) @@ -1620,11 +1601,11 @@ string Notepad_plus::getLangDesc(LangType langType, bool shortDesc) if (langType == L_USER) { - Buffer & currentBuf = _pEditView->getCurrentBuffer(); - if (currentBuf.isUserDefineLangExt()) + Buffer * currentBuf = _pEditView->getCurrentBuffer(); + if (currentBuf->isUserDefineLangExt()) { str2Show += " - "; - str2Show += currentBuf.getUserDefineLangName(); + str2Show += currentBuf->getUserDefineLangName(); } } return str2Show; @@ -1633,9 +1614,11 @@ string Notepad_plus::getLangDesc(LangType langType, bool shortDesc) BOOL Notepad_plus::notify(SCNotification *notification) { //Important, keep track of which element generated the message - bool isFromPrimary = (_mainEditView.getHSelf() == notification->nmhdr.hwndFrom); + 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) { @@ -1656,18 +1639,17 @@ BOOL Notepad_plus::notify(SCNotification *notification) break; case SCN_SAVEPOINTREACHED: - notifyView->setCurrentDocState(false); - notifyDocTab->updateCurrentTabItem(); - checkDocState(); - synchronise(); - break; - - case SCN_SAVEPOINTLEFT: - notifyView->setCurrentDocState(true); - notifyDocTab->updateCurrentTabItem(); - checkDocState(); - synchronise(); - break; + case SCN_SAVEPOINTLEFT: { + Buffer * buf = 0; + if (isFromPrimary) { + buf = _mainEditView.getCurrentBuffer(); + } else if (isFromSecondary) { + buf = _subEditView.getCurrentBuffer(); + } else { + break; //wrong scintilla + } + buf->setDirty(notification->nmhdr.code == SCN_SAVEPOINTLEFT); + break; } case SCN_MODIFYATTEMPTRO : // on fout rien @@ -1680,16 +1662,6 @@ BOOL Notepad_plus::notify(SCNotification *notification) case TCN_TABDROPPED: { TabBarPlus *sender = reinterpret_cast(notification->nmhdr.idFrom); - int destIndex = sender->getTabDraggedIndex(); - int scrIndex = sender->getSrcTabIndex(); - - // if the dragNdrop tab is not the current view tab, - // we have to set it to the current view tab - if (notification->nmhdr.hwndFrom != _pDocTab->getHSelf()) - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - - _pEditView->sortBuffer(destIndex, scrIndex); - _pEditView->setCurrentIndex(destIndex); if (notification->nmhdr.code == TCN_TABDROPPEDOUTSIDE) { @@ -1739,13 +1711,13 @@ BOOL Notepad_plus::notify(SCNotification *notification) } _tabPopupDropMenu.display(p); } - else if ((hWin == getNonCurrentDocTab()->getHSelf()) || - (hWin == getNonCurrentEditView()->getHSelf())) // In the another view group + else if ((hWin == _pNonDocTab->getHSelf()) || + (hWin == _pNonEditView->getHSelf())) // In the another view group { if (::GetKeyState(VK_LCONTROL) & 0x80000000) - docGotoAnotherEditView(MODE_CLONE); + docGotoAnotherEditView(TransferClone); else - docGotoAnotherEditView(MODE_TRANSFER); + docGotoAnotherEditView(TransferMove); } //else on fout rien!!! // It's non view group } @@ -1754,34 +1726,46 @@ BOOL Notepad_plus::notify(SCNotification *notification) case TCN_TABDELETE: { - if (notification->nmhdr.hwndFrom != _pDocTab->getHSelf()) - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - - fileClose(); + 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(); + break; + } + int open = 1; + if (isFromPrimary || isFromSecondary) + open = notifyDocTab->nbItem(); + doClose(bufferToClose, iView); + if (open == 1 && canHideView(iView)) + hideView(iView); break; } case TCN_SELCHANGE: { - char fullPath[MAX_PATH]; - + int iView = -1; if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf()) { - strcpy(fullPath, _mainDocTab.clickedUpdate()); - switchEditViewTo(MAIN_VIEW); - + iView = MAIN_VIEW; } else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf()) { - strcpy(fullPath, _subDocTab.clickedUpdate()); - switchEditViewTo(SUB_VIEW); + iView = SUB_VIEW; + } + else + { + break; } - PathRemoveFileSpec(fullPath); - setWorkingDir(fullPath); - //_pEditView->execute(SCI_SETLEXER, SCLEX_CONTAINER) - _linkTriggered = true; + switchEditViewTo(iView); + BufferID bufid = _pDocTab->getBufferByIndex(_pDocTab->getCurrentTabIndex()); + if (bufid != BUFFER_INVALID) + activateBuffer(bufid, iView); + break; } @@ -1839,10 +1823,8 @@ BOOL Notepad_plus::notify(SCNotification *notification) return TRUE; //break; - POINT p, clientPoint; + POINT p; ::GetCursorPos(&p); - clientPoint.x = p.x; - clientPoint.y = p.y; if (!_tabPopupMenu.isCreated()) { @@ -1943,16 +1925,15 @@ BOOL Notepad_plus::notify(SCNotification *notification) _tabPopupMenu.create(_hSelf, itemUnitArray); } - ::ScreenToClient(_pDocTab->getHSelf(), &clientPoint); - ::SendMessage(_pDocTab->getHSelf(), WM_LBUTTONDOWN, 2, MAKELONG(clientPoint.x, clientPoint.y)); - + bool isEnable = ((::GetMenuState(_mainMenuHandle, IDM_FILE_SAVE, MF_BYCOMMAND)&MF_DISABLED) == 0); _tabPopupMenu.enableItem(IDM_FILE_SAVE, isEnable); - bool isUserReadOnly = _pEditView->isCurrentBufUserReadOnly(); + Buffer * buf = _pEditView->getCurrentBuffer(); + bool isUserReadOnly = buf->getUserReadOnly(); _tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly); - bool isSysReadOnly = _pEditView->isCurrentBufSysReadOnly(); + bool isSysReadOnly = buf->getFileReadOnly(); _tabPopupMenu.enableItem(IDM_EDIT_SETREADONLY, !isSysReadOnly); _tabPopupMenu.enableItem(IDM_EDIT_CLEARREADONLY, isSysReadOnly); @@ -1978,7 +1959,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) { int lineClick = int(_pEditView->execute(SCI_LINEFROMPOSITION, notification->position)); - if (!showLines(lineClick)) + if (!_pEditView->markerMarginClick(lineClick)) bookmarkToggle(lineClick); } @@ -2043,11 +2024,15 @@ BOOL Notepad_plus::notify(SCNotification *notification) } else if (hWin == _mainDocTab.getHSelf()) { - tip = _mainEditView.getBufferAt(id).getFileName(); + BufferID idd = _mainDocTab.getBufferByIndex(id); + Buffer * buf = MainFileManager->getBufferByID(idd); + tip = buf->getFilePath(); } else if (hWin == _subDocTab.getHSelf()) { - tip = _subEditView.getBufferAt(id).getFileName(); + BufferID idd = _subDocTab.getBufferByIndex(id); + Buffer * buf = MainFileManager->getBufferByID(idd); + tip = buf->getFilePath(); } else break; @@ -2492,17 +2477,14 @@ void Notepad_plus::command(int id) case IDM_FILE_CLOSE: fileClose(); - checkSyncState(); break; case IDM_FILE_CLOSEALL: fileCloseAll(); - checkSyncState(); break; case IDM_FILE_CLOSEALL_BUT_CURRENT : fileCloseAllButCurrent(); - checkSyncState(); break; case IDM_FILE_SAVE : @@ -2518,7 +2500,7 @@ void Notepad_plus::command(int id) break; case IDM_FILE_SAVECOPYAS : - fileSaveAs(true); + fileSaveAs(BUFFER_INVALID, true); break; case IDM_FILE_LOADSESSION: @@ -2555,6 +2537,7 @@ void Notepad_plus::command(int id) case IDM_EDIT_CUT: _pEditView->execute(WM_CUT); + checkClipboard(); break; case IDM_EDIT_COPY: @@ -2651,23 +2634,20 @@ void Notepad_plus::command(int id) break; } case IDM_EDIT_FULLPATHTOCLIP : - { - str2Cliboard(_pEditView->getCurrentTitle()); - } - break; - case IDM_EDIT_CURRENTDIRTOCLIP : - { - char dir[MAX_PATH]; - strcpy(dir, _pEditView->getCurrentTitle()); - PathRemoveFileSpec((LPSTR)dir); - str2Cliboard(dir); - } - break; - case IDM_EDIT_FILENAMETOCLIP : { - str2Cliboard(PathFindFileName((LPSTR)_pEditView->getCurrentTitle())); + Buffer * buf = _pEditView->getCurrentBuffer(); + if (id == IDM_EDIT_FULLPATHTOCLIP) { + str2Cliboard(buf->getFilePath()); + } else if (id == IDM_EDIT_CURRENTDIRTOCLIP) { + char dir[MAX_PATH]; + strcpy(dir, buf->getFilePath()); + PathRemoveFileSpec((LPSTR)dir); + str2Cliboard(dir); + } else if (id == IDM_EDIT_FILENAMETOCLIP) { + str2Cliboard(buf->getFileName()); + } } break; @@ -2702,7 +2682,7 @@ void Notepad_plus::command(int id) _findReplaceDlg.doDialog((id == IDM_SEARCH_FIND)?FIND_DLG:REPLACE_DLG, _isRTL); _pEditView->getSelectedText(str, strSize); - _findReplaceDlg.setSearchText(str, _pEditView->getCurrentBuffer()._unicodeMode != uni8Bit); + _findReplaceDlg.setSearchText(str, _pEditView->getCurrentBuffer()->getUnicodeMode() != uni8Bit); if (isFirstTime) changeDlgLang(_findReplaceDlg.getHSelf(), "Find"); @@ -2722,7 +2702,7 @@ void Notepad_plus::command(int id) _incrementFindDlg.display(); _pEditView->getSelectedText(str, strSize); - _incrementFindDlg.setSearchText(str, _pEditView->getCurrentBuffer()._unicodeMode != uni8Bit); + _incrementFindDlg.setSearchText(str, _pEditView->getCurrentBuffer()->getUnicodeMode() != uni8Bit); } break; @@ -2841,7 +2821,7 @@ void Notepad_plus::command(int id) { ::ShowWindow(_pMainSplitter->getHSelf(), SW_HIDE); - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (bothActive()) _pMainWindow = &_subSplitter; else _pMainWindow = _pDocTab; @@ -2849,7 +2829,7 @@ void Notepad_plus::command(int id) ::SendMessage(_hSelf, WM_SIZE, 0, 0); udd->display(false); - _mainWindowStatus &= ~DOCK_MASK; + _mainWindowStatus &= ~WindowUserActive; } else if ((isUDDlgDocked)&&(!isUDDlgVisible)) { @@ -2859,7 +2839,7 @@ void Notepad_plus::command(int id) _pMainSplitter->init(_hInst, _hSelf); Window *pWindow; - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (bothActive()) pWindow = &_subSplitter; else pWindow = _pDocTab; @@ -2869,12 +2849,12 @@ void Notepad_plus::command(int id) _pMainWindow = _pMainSplitter; - _pMainSplitter->setWin0((_mainWindowStatus & TWO_VIEWS_MASK)?(Window *)&_subSplitter:(Window *)_pDocTab); + _pMainSplitter->setWin0((bothActive())?(Window *)&_subSplitter:(Window *)_pDocTab); ::SendMessage(_hSelf, WM_SIZE, 0, 0); _pMainWindow->display(); - _mainWindowStatus |= DOCK_MASK; + _mainWindowStatus |= WindowUserActive; } else if ((!isUDDlgDocked)&&(isUDDlgVisible)) { @@ -2954,25 +2934,21 @@ void Notepad_plus::command(int id) case IDM_EDIT_SETREADONLY: { - int check = (::GetMenuState(_mainMenuHandle, id, MF_BYCOMMAND) == MF_CHECKED)?MF_UNCHECKED:MF_CHECKED; - ::CheckMenuItem(_mainMenuHandle, id, MF_BYCOMMAND | check); - _pEditView->setCurrentDocReadOnlyByUser(check == MF_CHECKED); - _pDocTab->updateCurrentTabItem(); + Buffer * buf = _pEditView->getCurrentBuffer(); + buf->setUserReadOnly(!buf->getUserReadOnly()); } break; case IDM_EDIT_CLEARREADONLY: { - DWORD dwFileAttribs = ::GetFileAttributes(_pEditView->getCurrentBuffer().getFileName()); + Buffer * buf = _pEditView->getCurrentBuffer(); + + DWORD dwFileAttribs = ::GetFileAttributes(buf->getFileName()); dwFileAttribs ^= FILE_ATTRIBUTE_READONLY; - ::SetFileAttributes(_pEditView->getCurrentBuffer().getFileName(), dwFileAttribs); + ::SetFileAttributes(buf->getFileName(), dwFileAttribs); - _pEditView->execute(SCI_SETREADONLY,false); - _pEditView->updateCurrentDocSysReadOnlyStat(); - - _pDocTab->updateCurrentTabItem(); - enableCommand(IDM_EDIT_SETREADONLY, true, MENU); + buf->setFileReadOnly(false); } break; @@ -3248,18 +3224,7 @@ void Notepad_plus::command(int id) case IDM_VIEW_HIDELINES: { - CharacterRange range = _pEditView->getSelection(); - int startLine = _pEditView->execute(SCI_LINEFROMPOSITION, range.cpMin); - int endLine = _pEditView->execute(SCI_LINEFROMPOSITION, range.cpMax); - - if (startLine == 0) - startLine = 1; - if (endLine == _pEditView->lastZeroBasedLineNumber()) - endLine -= 1; - _pEditView->execute(SCI_HIDELINES, startLine, endLine); - _pEditView->execute(SCI_MARKERADD, startLine-1, MARK_HIDELINESBEGIN); - _pEditView->execute(SCI_MARKERADD, endLine+1, MARK_HIDELINESEND); - _hideLinesMarks.push_back(pair(startLine-1, endLine+1)); + _pEditView->hideLines(); break; } @@ -3326,12 +3291,12 @@ void Notepad_plus::command(int id) case IDM_FORMAT_TOUNIX : case IDM_FORMAT_TOMAC : { + Buffer * buf = _pEditView->getCurrentBuffer(); + int f = int((id == IDM_FORMAT_TODOS)?SC_EOL_CRLF:(id == IDM_FORMAT_TOUNIX)?SC_EOL_LF:SC_EOL_CR); - _pEditView->execute(SCI_SETEOLMODE, f); - _pEditView->execute(SCI_CONVERTEOLS, f); - (_pEditView->getCurrentBuffer()).setFormat((formatType)f); - enableConvertMenuItems((formatType)f); - setDisplayFormat((formatType)f); + + buf->setFormat((formatType)f); + _pEditView->execute(SCI_CONVERTEOLS, buf->getFormat()); break; } @@ -3341,6 +3306,8 @@ void Notepad_plus::command(int id) case IDM_FORMAT_UCS_2LE : case IDM_FORMAT_AS_UTF_8 : { + Buffer * buf = _pEditView->getCurrentBuffer(); + UniMode um; switch (id) { @@ -3363,16 +3330,11 @@ void Notepad_plus::command(int id) default : // IDM_FORMAT_ANSI um = uni8Bit; } - if (_pEditView->getCurrentBuffer().getUnicodeMode() != um) - { - _pEditView->getCurrentBuffer().setUnicodeMode(um); - _pDocTab->updateCurrentTabItem(); - checkDocState(); - synchronise(); - _pEditView->execute(SCI_SETCODEPAGE, (um != uni8Bit)?SC_CP_UTF8:0); - checkUnicodeMenuItems(um); - setUniModeText(um); + if (buf->getUnicodeMode() != um) + { + buf->setUnicodeMode(um); + buf->setDirty(true); } break; } @@ -3384,8 +3346,7 @@ void Notepad_plus::command(int id) case IDM_FORMAT_CONV2_UCS_2LE: { int idEncoding = -1; - Buffer & currentBuffer = _pEditView->getCurrentBuffer(); - UniMode um = currentBuffer._unicodeMode; + UniMode um = _pEditView->getCurrentBuffer()->getUnicodeMode(); switch(id) { @@ -3603,15 +3564,23 @@ void Notepad_plus::command(int id) } case IDM_VIEW_GOTO_ANOTHER_VIEW: - docGotoAnotherEditView(MODE_TRANSFER); + docGotoAnotherEditView(TransferMove); checkSyncState(); break; case IDM_VIEW_CLONE_TO_ANOTHER_VIEW: - docGotoAnotherEditView(MODE_CLONE); + docGotoAnotherEditView(TransferClone); checkSyncState(); break; + case IDM_VIEW_SWITCHTO_MAIN: + switchEditViewTo(MAIN_VIEW); + break; + + case IDM_VIEW_SWITCHTO_SUB: + switchEditViewTo(SUB_VIEW); + break; + case IDM_ABOUT: { bool isFirstTime = !_aboutDlg.isCreated(); @@ -3896,8 +3865,8 @@ void Notepad_plus::command(int id) case IDC_PREV_DOC : case IDC_NEXT_DOC : { - int nbDoc = _mainDocTab.isVisible()?_mainEditView.getNbDoc():0; - nbDoc += _subDocTab.isVisible()?_subEditView.getNbDoc():0; + int nbDoc = viewVisible(MAIN_VIEW)?_mainDocTab.nbItem():0; + nbDoc += viewVisible(SUB_VIEW)?_subDocTab.nbItem():0; bool doTaskList = ((NppParameters::getInstance())->getNppGUI())._doTaskList; if (nbDoc > 1) @@ -3920,28 +3889,22 @@ void Notepad_plus::command(int id) } break; - case IDM_OPEN_ALL_RECENT_FILE : - for (int i = IDM_FILEMENU_LASTONE + 1 ; i < (IDM_FILEMENU_LASTONE + _lastRecentFileList.getMaxNbLRF() + 1) ; i++) + case IDM_OPEN_ALL_RECENT_FILE : { + BufferID lastOne = BUFFER_INVALID; + int size = _lastRecentFileList.getSize(); + for (int i = size - 1; i >= 0; i--) { - char fn[MAX_PATH]; - int res = ::GetMenuString(_mainMenuHandle, i, fn, sizeof(fn), MF_BYCOMMAND); - if (res) - { - doOpen(fn); - } + BufferID test = doOpen(_lastRecentFileList.getIndex(i).c_str()); + if (test != BUFFER_INVALID) + lastOne = test; } - break; + if (lastOne != BUFFER_INVALID) { + switchToFile(lastOne); + } + break; } case IDM_CLEAN_RECENT_FILE_LIST : - for (int i = IDM_FILEMENU_LASTONE + 1 ; i < (IDM_FILEMENU_LASTONE + _lastRecentFileList.getMaxNbLRF() + 1) ; i++) - { - char fn[MAX_PATH]; - int res = ::GetMenuString(_mainMenuHandle, i, fn, sizeof(fn), MF_BYCOMMAND); - if (res) - { - _lastRecentFileList.remove(fn); - } - } + _lastRecentFileList.clear(); break; case IDM_EDIT_RTL : @@ -3950,7 +3913,7 @@ void Notepad_plus::command(int id) long exStyle = ::GetWindowLong(_pEditView->getHSelf(), GWL_EXSTYLE); exStyle = (id == IDM_EDIT_RTL)?exStyle|WS_EX_LAYOUTRTL:exStyle&(~WS_EX_LAYOUTRTL); ::SetWindowLong(_pEditView->getHSelf(), GWL_EXSTYLE, exStyle); - _pEditView->defineDocType(_pEditView->getCurrentDocType()); + //_pEditView->defineDocType(_pEditView->getCurrentDocType()); _pEditView->redraw(); } break; @@ -3958,7 +3921,7 @@ void Notepad_plus::command(int id) case IDM_WINDOW_WINDOWS : { WindowsDlg _windowsDlg; - _windowsDlg.init(_hInst, _hSelf, _pEditView); + _windowsDlg.init(_hInst, _hSelf, _pDocTab); TiXmlNode *dlgNode = NULL; if (_nativeLang) @@ -3976,23 +3939,16 @@ void Notepad_plus::command(int id) default : if (id > IDM_FILE_EXIT && id < (IDM_FILE_EXIT + _lastRecentFileList.getMaxNbLRF() + 1)) { - char fn[MAX_PATH]; - int res = ::GetMenuString(_mainMenuHandle, id, fn, sizeof(fn), MF_BYCOMMAND); - if (res) - { - if (doOpen(fn) == OPEN_SUCCESS) - { - setLangStatus(_pEditView->getCurrentDocType()); - } + BufferID lastOpened = doOpen(_lastRecentFileList.getItem(id).c_str()); + if (lastOpened != BUFFER_INVALID) { + switchToFile(lastOpened); } } else if ((id > IDM_LANG_USER) && (id < IDM_LANG_USER_LIMIT)) { char langName[langNameLenMax]; ::GetMenuString(_mainMenuHandle, id, langName, sizeof(langName), MF_BYCOMMAND); - _pEditView->setCurrentDocUserType(langName); - setLangStatus(L_USER); - checkLangsMenu(id); + _pEditView->getCurrentBuffer()->setLangType(L_USER, langName); } else if ((id >= IDM_LANG_EXTERNAL) && (id <= IDM_LANG_EXTERNAL_LIMIT)) { @@ -4112,80 +4068,68 @@ void Notepad_plus::command(int id) } -void Notepad_plus::setTitleWith(const char *filePath) +void Notepad_plus::setTitle() { - if (!filePath || !strcmp(filePath, "")) - return; + //Get the buffer + Buffer * buf = _pEditView->getCurrentBuffer(); - const size_t str2concatLen = MAX_PATH + 32; - char str2concat[str2concatLen]; - strcat(strcpy(str2concat, filePath), " - "); - strcat(str2concat, _className); - ::SetWindowText(_hSelf, str2concat); + string result = ""; + if (buf->isDirty()) { + result += "*"; + } + result += buf->getFilePath(); + result += " - "; + result += _className; + ::SetWindowText(_hSelf, result.c_str()); } void Notepad_plus::activateNextDoc(bool direction) { - int nbDoc = _pEditView->getNbDoc(); - if (!nbDoc) return; + int nbDoc = _pDocTab->nbItem(); - int curIndex = _pEditView->getCurrentDocIndex(); + int curIndex = _pDocTab->getCurrentTabIndex(); curIndex += (direction == dirUp)?-1:1; if (curIndex >= nbDoc) { - if (getNonCurrentDocTab()->isVisible()) - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); + if (viewVisible(otherView())) + switchEditViewTo(otherView()); curIndex = 0; } else if (curIndex < 0) { - if (getNonCurrentDocTab()->isVisible()) + if (viewVisible(otherView())) { - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - nbDoc = _pEditView->getNbDoc(); + switchEditViewTo(otherView()); + nbDoc = _pDocTab->nbItem(); } curIndex = nbDoc - 1; } - char *fullPath = _pDocTab->activate(curIndex); - setTitleWith(fullPath); - //checkDocState(); - - char dirPath[MAX_PATH]; - - strcpy(dirPath, fullPath); - PathRemoveFileSpec(dirPath); - setWorkingDir(dirPath); + BufferID id = _pDocTab->getBufferByIndex(curIndex); + activateBuffer(id, currentView()); } - void Notepad_plus::activateDoc(int pos) { - int nbDoc = _pEditView->getNbDoc(); - if (!nbDoc) return; - - if (pos == _pEditView->getCurrentDocIndex()) + int nbDoc = _pDocTab->nbItem(); + if (pos == _pDocTab->getCurrentTabIndex()) { - (_pEditView->getCurrentBuffer()).increaseRecentTag(); + Buffer * buf = _pEditView->getCurrentBuffer(); + buf->increaseRecentTag(); return; } if (pos >= 0 && pos < nbDoc) { - char *fullPath = _pDocTab->activate(pos); - setTitleWith(fullPath); - //checkDocState(); - char dirPath[MAX_PATH]; - - strcpy(dirPath, fullPath); - PathRemoveFileSpec(dirPath); - setWorkingDir(dirPath); + BufferID id = _pDocTab->getBufferByIndex(pos); + activateBuffer(id, currentView()); } } void Notepad_plus::updateStatusBar() { + Buffer * buf = _pEditView->getCurrentBuffer(); char strLnCol[64]; sprintf(strLnCol, "Ln : %d Col : %d Sel : %d",\ (_pEditView->getCurrentLineNumber() + 1), \ @@ -4197,9 +4141,6 @@ void Notepad_plus::updateStatusBar() char strDonLen[64]; sprintf(strDonLen, "nb char : %d", _pEditView->getCurrentDocLen()); _statusBar.setText(strDonLen, STATUSBAR_DOC_SIZE); - - setDisplayFormat((_pEditView->getCurrentBuffer()).getFormat()); - setUniModeText(_pEditView->getCurrentBuffer().getUnicodeMode()); _statusBar.setText(_pEditView->execute(SCI_GETOVERTYPE) ? "OVR" : "INS", STATUSBAR_TYPING_MODE); } @@ -4225,13 +4166,19 @@ void Notepad_plus::dropFiles(HDROP hdrop) } int filesDropped = ::DragQueryFile(hdrop, 0xffffffff, NULL, 0); + BufferID lastOpened = BUFFER_INVALID; for (int i = 0 ; i < filesDropped ; ++i) { char pathDropped[MAX_PATH]; ::DragQueryFile(hdrop, i, pathDropped, sizeof(pathDropped)); - doOpen(pathDropped); + BufferID test = doOpen(pathDropped); + if (test != BUFFER_INVALID) + lastOpened = test; //setLangStatus(_pEditView->getCurrentDocType()); } + if (lastOpened != BUFFER_INVALID) { + switchToFile(lastOpened); + } ::DragFinish(hdrop); // Put Notepad_plus to forefront // May not work for Win2k, but OK for lower versions @@ -4247,332 +4194,8 @@ void Notepad_plus::dropFiles(HDROP hdrop) void Notepad_plus::checkModifiedDocument() { - const int NB_VIEW = 2; - struct ViewInfo { - int id; - ScintillaEditView * sv; - DocTabView * dtv; - int currentIndex; - bool toBeActivated; - }; - - ViewInfo viewInfoArray[NB_VIEW]; - - // the oder (1.current view 2.non current view) is important - // to synchronize with "hideCurrentView" function - viewInfoArray[0].id = getCurrentView(); - viewInfoArray[0].sv = _pEditView; - viewInfoArray[0].dtv = _pDocTab; - viewInfoArray[0].currentIndex = _pEditView->getCurrentDocIndex(); - viewInfoArray[0].toBeActivated = false; - - viewInfoArray[1].id = getNonCurrentView(); - viewInfoArray[1].sv = getNonCurrentEditView(); - viewInfoArray[1].dtv = getNonCurrentDocTab(); - viewInfoArray[1].currentIndex = viewInfoArray[1].sv->getCurrentDocIndex(); - viewInfoArray[1].toBeActivated = false; - - NppParameters *pNppParam = NppParameters::getInstance(); - const NppGUI & nppGUI = pNppParam->getNppGUI(); - bool autoUpdate = (nppGUI._fileAutoDetection == cdAutoUpdate) || (nppGUI._fileAutoDetection == cdAutoUpdateGo2end); - - _subEditView.getCurrentDocIndex(); - for (int j = 0 ; j < NB_VIEW ; j++) - { - ViewInfo & vi = viewInfoArray[j]; - if (vi.sv->isVisible()) - { - for (int i = ((vi.sv)->getNbDoc()-1) ; i >= 0 ; i--) - { - Buffer & docBuf = vi.sv->getBufferAt(i); - docFileStaus fStatus = docBuf.checkFileState(); - bool update = !docBuf.isDirty() && autoUpdate; - - if (fStatus == MODIFIED_FROM_OUTSIDE) - { - // If npp is minimized, bring it up to the top - if (::IsIconic(_hSelf)) - ::ShowWindow(_hSelf, SW_SHOWNORMAL); - - if (update) - { - docBuf._reloadOnSwitchBack = true; - // for 2 views, if it's current doc, then reload immediately - if (vi.currentIndex == i) - { - vi.toBeActivated = true; - if (j == 0) // 0 == current view - { - _activeAppInf._isActivated = false; - } - } - } - else if (doReloadOrNot(docBuf.getFileName()) == IDYES) - { - docBuf._reloadOnSwitchBack = true; - setTitleWith(vi.dtv->activate(i)); - // if it's a non current view, make it as the current view - if (j == 1) - switchEditViewTo(getNonCurrentView()); - } - - if (_activeAppInf._isActivated) - { - int curPos = _pEditView->execute(SCI_GETCURRENTPOS); - ::PostMessage(_pEditView->getHSelf(), WM_LBUTTONUP, 0, 0); - ::PostMessage(_pEditView->getHSelf(), SCI_SETSEL, curPos, curPos); - _activeAppInf._isActivated = false; - } - docBuf.updatTimeStamp(); - } - else if (fStatus == FILE_DELETED && !docBuf._dontBotherMeAnymore) - { - if (::IsIconic(_hSelf)) - ::ShowWindow(_hSelf, SW_SHOWNORMAL); - - if (doCloseOrNot(docBuf.getFileName()) == IDNO) - { - vi.dtv->activate(i); - if ((vi.sv->getNbDoc() == 1) && (_mainWindowStatus & TWO_VIEWS_MASK)) - { - setTitleWith(vi.dtv->closeCurrentDoc()); - hideCurrentView(); - } - else - setTitleWith(vi.dtv->closeCurrentDoc()); - } - else - docBuf._dontBotherMeAnymore = true; - - if (_activeAppInf._isActivated) - { - int curPos = _pEditView->execute(SCI_GETCURRENTPOS); - ::PostMessage(_pEditView->getHSelf(), WM_LBUTTONUP, 0, 0); - ::PostMessage(_pEditView->getHSelf(), SCI_SETSEL, curPos, curPos); - _activeAppInf._isActivated = false; - } - } - - bool isReadOnly = vi.sv->isCurrentBufReadOnly(); - vi.sv->execute(SCI_SETREADONLY, isReadOnly); - } - } - } - - if (autoUpdate) - { - if (viewInfoArray[0].toBeActivated) - { - switchEditViewTo(viewInfoArray[0].id); - } - - if (viewInfoArray[1].toBeActivated) - { - switchEditViewTo(viewInfoArray[1].id); - switchEditViewTo(viewInfoArray[0].id); - } - } -} - -void Notepad_plus::reloadOnSwitchBack() -{ - Buffer & buf = _pEditView->getCurrentBuffer(); - - if (buf._reloadOnSwitchBack) - { - if (_pEditView->isCurrentBufReadOnly()) - _pEditView->execute(SCI_SETREADONLY, FALSE); - - reload(buf.getFileName()); - - NppParameters *pNppParam = NppParameters::getInstance(); - const NppGUI & nppGUI = pNppParam->getNppGUI(); - if (nppGUI._fileAutoDetection == cdAutoUpdateGo2end || nppGUI._fileAutoDetection == cdGo2end) - { - int line = _pEditView->lastZeroBasedLineNumber(); - _pEditView->gotoLine(line); - } - - if (_pEditView->isCurrentBufReadOnly()) - _pEditView->execute(SCI_SETREADONLY, TRUE); - - buf._reloadOnSwitchBack = false; - } -} - -void Notepad_plus::hideCurrentView() -{ - if (_mainWindowStatus & DOCK_MASK) - { - _pMainSplitter->setWin0(getNonCurrentDocTab()); - } - else // otherwise the main window is the spltter container that we just created - _pMainWindow = getNonCurrentDocTab(); - - _subSplitter.display(false); - _pEditView->display(false); - _pDocTab->display(false); - - // resize the main window - ::SendMessage(_hSelf, WM_SIZE, 0, 0); - - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - _mainWindowStatus &= ~TWO_VIEWS_MASK; -} - -bool Notepad_plus::fileClose() -{ - // Notify plugins that current file is about to be closed - SCNotification scnN; - scnN.nmhdr.code = NPPN_FILEBEFORECLOSE; - scnN.nmhdr.hwndFrom = _hSelf; - scnN.nmhdr.idFrom = 0; - _pluginsManager.notify(&scnN); - - int res; - bool isDirty = _pEditView->isCurrentDocDirty(); - - //process the fileNamePath into LRF - const char *fileNamePath = _pEditView->getCurrentTitle(); - - if ((!isDirty) && (Buffer::isUntitled(fileNamePath)) && (_pEditView->getNbDoc() == 1) && (!getNonCurrentDocTab()->isVisible())) - return true; - - if (isDirty) - { - if ((res = doSaveOrNot(_pEditView->getCurrentTitle())) == IDYES) - { - if (!fileSave()) // the cancel button of savdialog is pressed - return false; - } - else if (res == IDCANCEL) - return false; - // else IDNO we continue - } - - //si ce n'est pas untited(avec prefixe "new "), on fait le traitement - if (!Buffer::isUntitled(fileNamePath)) - { - _lastRecentFileList.add(fileNamePath); - } - - - if ((_pEditView->getNbDoc() == 1) && (_mainWindowStatus & TWO_VIEWS_MASK)) - { - _pDocTab->closeCurrentDoc(); - hideCurrentView(); - scnN.nmhdr.code = NPPN_FILECLOSED; - _pluginsManager.notify(&scnN); - return true; - } - - char fullPath[MAX_PATH]; - strcpy(fullPath, _pDocTab->closeCurrentDoc()); - setTitleWith(fullPath); - - PathRemoveFileSpec(fullPath); - setWorkingDir(fullPath); - - _linkTriggered = true; - ::SendMessage(_hSelf, NPPM_INTERNAL_DOCSWITCHIN, 0, 0); - - // Notify plugins that current file is closed - scnN.nmhdr.code = NPPN_FILECLOSED; - _pluginsManager.notify(&scnN); - - return true; -} - -bool Notepad_plus::fileCloseAll() -{ - if (_mainWindowStatus & TWO_VIEWS_MASK) - { - while (_pEditView->getNbDoc() > 1) - if (!fileClose()) - return false; - - if (!fileClose()) - return false; - } - - while (_pEditView->getNbDoc() > 1) - if (!fileClose()) - return false; - return fileClose(); -} - -bool Notepad_plus::fileCloseAllButCurrent() -{ - int curIndex = _pEditView->getCurrentDocIndex(); - _pEditView->activateDocAt(0); - - for (int i = 0 ; i < curIndex ; i++) - if (!fileClose()) - { - curIndex -= i; - _pDocTab->activate(curIndex); - return false; - } - - if (_pEditView->getNbDoc() > 1) - { - _pDocTab->activate(1); - while (_pEditView->getNbDoc() > 1) - if (!fileClose()) - return false; - } - if (_mainWindowStatus & TWO_VIEWS_MASK) - { - switchEditViewTo(getNonCurrentView()); - while (_pEditView->getNbDoc() > 1) - if (!fileClose()) - return false; - return fileClose(); - } - return true; -} - -void Notepad_plus::reload(const char *fileName) -{ - Utf8_16_Read UnicodeConvertor; - Buffer & buffer = _pEditView->getCurrentBuffer(); - - FILE *fp = fopen(fileName, "rb"); - if (fp) - { - // It's VERY IMPORTANT to reset the view - _pEditView->execute(SCI_CLEARALL); - - char data[blockSize]; - - size_t lenFile = fread(data, 1, sizeof(data), fp); - while (lenFile > 0) { - lenFile = UnicodeConvertor.convert(data, lenFile); - _pEditView->execute(SCI_ADDTEXT, lenFile, reinterpret_cast(UnicodeConvertor.getNewBuf())); - lenFile = int(fread(data, 1, sizeof(data), fp)); - } - fclose(fp); - - UniMode unicodeMode = static_cast(UnicodeConvertor.getEncoding()); - buffer.setUnicodeMode(unicodeMode); - - if (unicodeMode != uni8Bit) - // Override the code page if Unicode - _pEditView->execute(SCI_SETCODEPAGE, SC_CP_UTF8); - - _pEditView->getFocus(); - _pEditView->execute(SCI_SETSAVEPOINT); - _pEditView->execute(EM_EMPTYUNDOBUFFER); - _pEditView->restoreCurrentPos(); - } - else - { - char msg[MAX_PATH + 100]; - strcpy(msg, "Can not open file \""); - strcat(msg, fileName); - strcat(msg, "\"."); - ::MessageBox(_hSelf, msg, "ERR", MB_OK); - } + //this will trigger buffer updates. If the status changes, Notepad++ will be informed and can do its magic + MainFileManager->checkFilesystemChanges(); } void Notepad_plus::getMainClientRect(RECT &rc) const @@ -4582,6 +4205,201 @@ void Notepad_plus::getMainClientRect(RECT &rc) const rc.bottom -= rc.top + _rebarBottom.getHeight() + _statusBar.getHeight(); } +void Notepad_plus::showView(int whichOne) { + if (viewVisible(whichOne)) //no use making visible view visible + return; + + if (_mainWindowStatus & WindowUserActive) { + _pMainSplitter->setWin0(&_subSplitter); + _pMainWindow = _pMainSplitter; + } else { + _pMainWindow = &_subSplitter; + } + + if (whichOne == MAIN_VIEW) { + _mainEditView.display(true); + _mainDocTab.display(true); + } else if (whichOne == SUB_VIEW) { + _subEditView.display(true); + _subDocTab.display(true); + } + _pMainWindow->display(true); + + _mainWindowStatus |= (whichOne==MAIN_VIEW)?WindowMainActive:WindowSubActive; + + //Send sizing info to make windows fit + ::SendMessage(_hSelf, WM_SIZE, 0, 0); +} + +bool Notepad_plus::viewVisible(int whichOne) { + int viewToCheck = (whichOne == SUB_VIEW?WindowSubActive:WindowMainActive); + return (_mainWindowStatus & viewToCheck) != 0; +} + +void Notepad_plus::hideCurrentView() +{ + hideView(currentView()); +} + +void Notepad_plus::hideView(int whichOne) +{ + if (!(bothActive())) //cannot close if not both views visible + return; + + Window * windowToSet = (whichOne == MAIN_VIEW)?&_subDocTab:&_mainDocTab; + if (_mainWindowStatus & WindowUserActive) + { + _pMainSplitter->setWin0(windowToSet); + } + else // otherwise the main window is the spltter container that we just created + _pMainWindow = windowToSet; + + _subSplitter.display(false); //hide splitter + //hide scintilla and doctab + if (whichOne == MAIN_VIEW) { + _mainEditView.display(false); + _mainDocTab.display(false); + } else if (whichOne == SUB_VIEW) { + _subEditView.display(false); + _subDocTab.display(false); + } + + // resize the main window + ::SendMessage(_hSelf, WM_SIZE, 0, 0); + + switchEditViewTo(otherFromView(whichOne)); + int viewToDisable = (whichOne == SUB_VIEW?WindowSubActive:WindowMainActive); + _mainWindowStatus &= ~viewToDisable; +} + +int Notepad_plus::currentView() { + return _activeView; +} + +int Notepad_plus::otherView() { + return (_activeView == MAIN_VIEW?SUB_VIEW:MAIN_VIEW); +} + +int Notepad_plus::otherFromView(int whichOne) { + return (whichOne == MAIN_VIEW?SUB_VIEW:MAIN_VIEW); +} + +bool Notepad_plus::canHideView(int whichOne) { + if (!viewVisible(whichOne)) + return false; //cannot hide hidden view + if (!bothActive()) + return false; //cannot hide only window + DocTabView * tabToCheck = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab; + Buffer * buf = MainFileManager->getBufferByID(tabToCheck->getBufferByIndex(0)); + bool canHide = ((tabToCheck->nbItem() == 1) && !buf->isDirty() && buf->isUntitled()); + return canHide; +} + +void Notepad_plus::loadBufferIntoView(BufferID id, int whichOne, bool dontClose) { + DocTabView * tabToOpen = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab; + ScintillaEditView * viewToOpen = (whichOne == MAIN_VIEW)?&_mainEditView:&_subEditView; + + //check if buffer exists + int index = tabToOpen->getIndexByBuffer(id); + if (index != -1) //already open, done + return; + + BufferID idToClose = BUFFER_INVALID; + //Check if the tab has a single clean buffer. Close it if so + if (!dontClose && tabToOpen->nbItem() == 1) { + idToClose = tabToOpen->getBufferByIndex(0); + Buffer * buf = MainFileManager->getBufferByID(idToClose); + if (buf->isDirty() || !buf->isUntitled()) { + idToClose = BUFFER_INVALID; + } + } + + MainFileManager->addBufferReference(id, viewToOpen); + //viewToOpen->activateBuffer(id); + //activateBuffer(id, whichOne); + + if (idToClose != BUFFER_INVALID) { //close clean doc. Use special logic to prevent flicker of tab showing then hiding + //removeBufferFromView(idToClose, whichOne); + tabToOpen->setBuffer(0, id); //index 0 since only one open + activateBuffer(id, whichOne); //activate. DocTab already activated but not a problem + MainFileManager->closeBuffer(idToClose, viewToOpen); //delete the buffer + } else { + tabToOpen->addBuffer(id); + } +} + +void Notepad_plus::removeBufferFromView(BufferID id, int whichOne) { + DocTabView * tabToClose = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab; + ScintillaEditView * viewToClose = (whichOne == MAIN_VIEW)?&_mainEditView:&_subEditView; + + //check if buffer exists + int index = tabToClose->getIndexByBuffer(id); + if (index == -1) //doesnt exist, done + return; + + Buffer * buf = MainFileManager->getBufferByID(id); + + //Cannot close doc if last and clean + if (tabToClose->nbItem() == 1) { + if (!buf->isDirty() && buf->isUntitled()) { + return; //done + } + } + + int active = tabToClose->getCurrentTabIndex(); + if (active == index) { //need an alternative (close real doc, put empty one back + if (tabToClose->nbItem() == 1) { //need alternative doc, add new one. Use special logic to prevent flicker of adding new tab then closing other + //loadBufferIntoView(newID, whichOne); + //viewToOpen->activateBuffer(id); + BufferID newID = MainFileManager->newEmptyDocument(); + MainFileManager->addBufferReference(newID, viewToClose); + tabToClose->setBuffer(0, newID); //can safely use id 0, last (only) tab open + activateBuffer(newID, whichOne); //activate. DocTab already activated but not a problem + } else { + int toActivate = 0; + //activate next doc, otherwise prev if not possible + if (active == tabToClose->nbItem() - 1) { //prev + toActivate = active - 1; + } else { + toActivate = active; //activate the 'active' index. Since we remove the tab first, the indices shift (on the right side) + } + tabToClose->deletItemAt(index); //delete first + activateBuffer(tabToClose->getBufferByIndex(toActivate), whichOne); //then activate. The prevent jumpy tab behaviour + + } + } else { + tabToClose->deletItemAt(index); + } + + MainFileManager->closeBuffer(id, viewToClose); +} + +int Notepad_plus::switchEditViewTo(int gid) +{ + if (currentView() == gid) { //make sure focus is ok, then leave + _pEditView->getFocus(); //set the focus + return gid; + } + if (!viewVisible(gid)) + return currentView(); //cannot activate invisible view + int oldView = currentView(); + int newView = otherView(); + + _activeView = newView; + //Good old switcheroo + DocTabView * tempTab = _pDocTab; + _pDocTab = _pNonDocTab; + _pNonDocTab = tempTab; + ScintillaEditView * tempView = _pEditView; + _pEditView = _pNonEditView; + _pNonEditView = tempView; + + _pEditView->getFocus(); //set the focus + + notifyBufferActivated(_pEditView->getCurrentBufferID(), currentView()); + return oldView; +} + void Notepad_plus::dockUserDlg() { if (!_pMainSplitter) @@ -4590,7 +4408,7 @@ void Notepad_plus::dockUserDlg() _pMainSplitter->init(_hInst, _hSelf); Window *pWindow; - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (_mainWindowStatus & (WindowMainActive | WindowSubActive)) pWindow = &_subSplitter; else pWindow = _pDocTab; @@ -4598,14 +4416,14 @@ void Notepad_plus::dockUserDlg() _pMainSplitter->create(pWindow, ScintillaEditView::getUserDefineDlg(), 8, RIGHT_FIX, 45); } - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (bothActive()) _pMainSplitter->setWin0(&_subSplitter); else _pMainSplitter->setWin0(_pDocTab); _pMainSplitter->display(); - _mainWindowStatus |= DOCK_MASK; + _mainWindowStatus |= WindowUserActive; _pMainWindow = _pMainSplitter; ::SendMessage(_hSelf, WM_SIZE, 0, 0); @@ -4616,128 +4434,70 @@ void Notepad_plus::undockUserDlg() // a cause de surchargement de "display" ::ShowWindow(_pMainSplitter->getHSelf(), SW_HIDE); - if (_mainWindowStatus & TWO_VIEWS_MASK) + if (bothActive()) _pMainWindow = &_subSplitter; else _pMainWindow = _pDocTab; ::SendMessage(_hSelf, WM_SIZE, 0, 0); - _mainWindowStatus &= ~DOCK_MASK; + _mainWindowStatus &= ~WindowUserActive; (ScintillaEditView::getUserDefineDlg())->display(); //(_pEditView->getUserDefineDlg())->display(); } -void Notepad_plus::docGotoAnotherEditView(bool mode) +void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode) { - if (!(_mainWindowStatus & TWO_VIEWS_MASK)) - { - // if there's dock dialog, it means there's also a splitter container - // we replace the right window by sub-spltter container that we just created - if (_mainWindowStatus & DOCK_MASK) - { - _pMainSplitter->setWin0(&_subSplitter); - _pMainWindow = _pMainSplitter; - } - else // otherwise the main window is the spltter container that we just created - _pMainWindow = &_subSplitter; - - // resize the main window - ::SendMessage(_hSelf, WM_SIZE, 0, 0); - - getNonCurrentEditView()->display(); - getNonCurrentDocTab()->display(); - - _pMainWindow->display(); - - // update the main window status - _mainWindowStatus |= TWO_VIEWS_MASK; - } - - // Bon, define the source view and the dest view - // source view - DocTabView *pSrcDocTab; - ScintillaEditView *pSrcEditView; - if (getCurrentView() == MAIN_VIEW) - { - // make dest view - switchEditViewTo(SUB_VIEW); - - // make source view - pSrcDocTab = &_mainDocTab; - pSrcEditView = &_mainEditView; - - } - else - { - // make dest view : _pDocTab & _pEditView - switchEditViewTo(MAIN_VIEW); - - // make source view - pSrcDocTab = &_subDocTab; - pSrcEditView = &_subEditView; - } - - // Maintenant, we begin to manipulate the source and the dest: - // 1. Save the current position of the source view to transfer - pSrcEditView->saveCurrentPos(); - - // 2. Retrieve the current buffer from the source - Buffer & buf = pSrcEditView->getCurrentBuffer(); - - // 3. See if the file to transfer exist in the dest view - // if so, we don't transfer the file(buffer) - // but activate the opened document in the dest view then beat it - int i; - if ( (i = _pDocTab->find(buf.getFileName())) != -1) - { - setTitleWith(_pDocTab->activate(i)); - _pDocTab->getFocus(); - return; + //First put the doc in the other view if not present (if it is, activate it). + //Then if needed close in the original tab + BufferID current = _pEditView->getCurrentBufferID(); + int viewToGo = otherView(); + int indexFound = _pNonDocTab->getIndexByBuffer(current); + if (indexFound != -1) { //activate it + activateBuffer(current, otherView()); + } else { //open the document, also copying the position + loadBufferIntoView(current, viewToGo); + Buffer * buf = MainFileManager->getBufferByID(current); + _pEditView->saveCurrentPos(); //allow copying of position + buf->setPosition(buf->getPosition(_pEditView), _pNonEditView); + _pNonEditView->restoreCurrentPos(); //set position + activateBuffer(current, otherView()); } - // 4. Transfer the file (buffer) into the dest view - bool isNewDoc2Close = false; + //Open the view if it was hidden + int viewToOpen = (viewToGo == SUB_VIEW?WindowSubActive:WindowMainActive); + if (!(_mainWindowStatus & viewToOpen)) { + showView(viewToGo); + } - if ((_pEditView->getNbDoc() == 1) - && Buffer::isUntitled(_pEditView->getCurrentTitle()) - && (!_pEditView->isCurrentDocDirty()) && (_pEditView->getCurrentDocLen() == 0)) - { - isNewDoc2Close = true; - } + //Close the document if we transfered the document instead of cloning it + if (mode == TransferMove) { + //just close the activate document, since thats the one we moved (no search) + doClose(_pEditView->getCurrentBufferID(), currentView()); + if (canHideView(currentView())) + hideView(currentView()); + } // else it was cone, so leave it - setTitleWith(_pDocTab->newDoc(buf)); - _pDocTab->updateCurrentTabItem(NULL); + //Activate the other view since thats where the document went + switchEditViewTo(viewToGo); - if (isNewDoc2Close) - _pDocTab->closeDocAt(0); + //_linkTriggered = true; +} - // 5. If it's the clone mode, we keep the document to transfer - // in the source view (do nothing). If it's the transfer mode - // we remove the file (buffer) from the source view - - if (mode != MODE_CLONE) - { - // Make focus to the source view - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - - if (_pEditView->getNbDoc() == 1) - { - // close the current doc in the dest view - _pDocTab->closeCurrentDoc(); - hideCurrentView(); - } - else - { - // close the current doc in the dest view - _pDocTab->closeCurrentDoc(); - - // return to state where the focus is on dest view - switchEditViewTo((getCurrentView() == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW); - } - } - //printInt(getCurrentView()); - _linkTriggered = true; +bool Notepad_plus::activateBuffer(BufferID id, int whichOne) { + if (whichOne == MAIN_VIEW) { + if (_mainDocTab.activateBuffer(id)) //only activate if possible + _mainEditView.activateBuffer(id); + else + return false; + } else { + if (_subDocTab.activateBuffer(id)) + _subEditView.activateBuffer(id); + else + return false; + } + notifyBufferActivated(id, whichOne); + return true; } void Notepad_plus::bookmarkNext(bool forwardScan) @@ -4763,23 +4523,6 @@ void Notepad_plus::bookmarkNext(bool forwardScan) _pEditView->execute(SCI_GOTOLINE, nextLine); } -int Notepad_plus::switchEditViewTo(int gid) -{ - int oldView = getCurrentView(); - _pDocTab = (gid == MAIN_VIEW)?&_mainDocTab:&_subDocTab; - _pEditView = (gid == MAIN_VIEW)?&_mainEditView:&_subEditView; - _pEditView->beSwitched(); - _pEditView->getFocus(); - - //checkDocState(); - setTitleWith(_pEditView->getCurrentTitle()); - - ::InvalidateRect(_mainDocTab.getHSelf(), NULL, TRUE); - ::InvalidateRect(_subDocTab.getHSelf(), NULL, TRUE); - ::SendMessage(_hSelf, NPPM_INTERNAL_DOCSWITCHIN, 0, 0); - return oldView; -} - void Notepad_plus::dynamicCheckMenuAndTB() const { // Visibility of 3 margins @@ -4838,8 +4581,8 @@ void Notepad_plus::dynamicCheckMenuAndTB() const checkMenuItem(IDM_VIEW_WRAP_SYMBOL, _pEditView->isWrapSymbolVisible()); //Format conversion - enableConvertMenuItems((_pEditView->getCurrentBuffer()).getFormat()); - checkUnicodeMenuItems((_pEditView->getCurrentBuffer()).getUnicodeMode()); + enableConvertMenuItems(_pEditView->getCurrentBuffer()->getFormat()); + checkUnicodeMenuItems(_pEditView->getCurrentBuffer()->getUnicodeMode()); //Syncronized scrolling } @@ -5373,16 +5116,16 @@ bool Notepad_plus::doBlockComment(comment_mode currCommentMode) const char *commentLineSybol; string symbol; - Buffer & buf = _pEditView->getCurrentBuffer(); - if (buf._lang == L_USER) + Buffer * buf = _pEditView->getCurrentBuffer(); + if (buf->getLangType() == L_USER) { - UserLangContainer & userLangContainer = NppParameters::getInstance()->getULCFromName(buf._userLangExt); + UserLangContainer & userLangContainer = NppParameters::getInstance()->getULCFromName(buf->getUserDefineLangName()); //::MessageBox(NULL, userLangContainer._keywordLists[4], "User", MB_OK); symbol = extractSymbol('0', userLangContainer._keywordLists[4]); commentLineSybol = symbol.c_str(); } else - commentLineSybol = buf.getCommentLineSymbol(); + commentLineSybol = buf->getCommentLineSymbol(); if ((!commentLineSybol) || (!commentLineSybol[0])) @@ -5489,10 +5232,10 @@ bool Notepad_plus::doStreamComment() string symbolStart; string symbolEnd; - Buffer & buf = _pEditView->getCurrentBuffer(); - if (buf._lang == L_USER) + Buffer * buf = _pEditView->getCurrentBuffer(); + if (buf->getLangType() == L_USER) { - UserLangContainer & userLangContainer = NppParameters::getInstance()->getULCFromName(buf._userLangExt); + UserLangContainer & userLangContainer = NppParameters::getInstance()->getULCFromName(buf->getUserDefineLangName()); symbolStart = extractSymbol('1', userLangContainer._keywordLists[4]); commentStart = symbolStart.c_str(); symbolEnd = extractSymbol('2', userLangContainer._keywordLists[4]); @@ -5500,8 +5243,8 @@ bool Notepad_plus::doStreamComment() } else { - commentStart = _pEditView->getCurrentBuffer().getCommentStart(); - commentEnd = _pEditView->getCurrentBuffer().getCommentEnd(); + commentStart = buf->getCommentStart(); + commentEnd = buf->getCommentEnd(); } if ((!commentStart) || (!commentStart[0])) @@ -5633,26 +5376,27 @@ void Notepad_plus::changeToolBarIcons() _toolBar.changeIcons(_customIconVect[i].listIndex, _customIconVect[i].iconIndex, (_customIconVect[i].iconLocation).c_str()); } -bool Notepad_plus::switchToFile(const char *fileName) +bool Notepad_plus::switchToFile(BufferID id) { - if (!fileName) return false; - int i = - 1; - int iView; + int i = 0; + int iView = currentView(); + if (id == BUFFER_INVALID) + return false; - if ((i = _mainDocTab.find(fileName)) != -1) + if ((i = _pDocTab->getIndexByBuffer(id)) != -1) { - iView = MAIN_VIEW; + iView = currentView(); } - else if ((i = _subDocTab.find(fileName)) != -1) + else if ((i = _pNonDocTab->getIndexByBuffer(id)) != -1) { - iView = SUB_VIEW; + iView = otherView(); } if (i != -1) { switchEditViewTo(iView); - setTitleWith(_pDocTab->activate(i)); - _pEditView->getFocus(); + //_pDocTab->activateAt(i); + activateBuffer(id, currentView()); return true; } return false; @@ -5722,36 +5466,27 @@ ToolBarButtonUnit toolBarIcons[] = { void Notepad_plus::getTaskListInfo(TaskListInfo *tli) { - int iView = getCurrentView(); - ScintillaEditView & currentView = (iView == MAIN_VIEW)?_mainEditView:_subEditView; - ScintillaEditView & nonCurrentView = (iView == MAIN_VIEW)?_subEditView:_mainEditView; - int nonCurrentiView = (iView == MAIN_VIEW)?SUB_VIEW:MAIN_VIEW; - - size_t currentNbDoc = currentView.getNbDoc(); - size_t nonCurrentNbDoc; + size_t currentNbDoc = _pDocTab->nbItem(); + size_t nonCurrentNbDoc = _pNonDocTab->nbItem(); tli->_currentIndex = 0; - if (iView == MAIN_VIEW) - { - nonCurrentNbDoc = _subDocTab.isVisible()?_subEditView.getNbDoc():0; - } - else - { - nonCurrentNbDoc = _mainDocTab.isVisible()?_mainEditView.getNbDoc():0; - } + if (!viewVisible(otherView())) + nonCurrentNbDoc = 0; for (size_t i = 0 ; i < currentNbDoc ; i++) { - Buffer & b = currentView.getBufferAt(i); - int status = b.isReadOnly()?tb_ro:(b.isDirty()?tb_unsaved:tb_saved); - tli->_tlfsLst.push_back(TaskLstFnStatus(iView,i,b._fullPathName, status)); + BufferID bufID = _pDocTab->getBufferByIndex(i); + Buffer * b = MainFileManager->getBufferByID(bufID); + int status = b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved); + tli->_tlfsLst.push_back(TaskLstFnStatus(currentView(), i, b->getFilePath(), status)); } for (size_t i = 0 ; i < nonCurrentNbDoc ; i++) { - Buffer & b = nonCurrentView.getBufferAt(i); - int status = b.isReadOnly()?tb_ro:(b.isDirty()?tb_unsaved:tb_saved); - tli->_tlfsLst.push_back(TaskLstFnStatus(nonCurrentiView,i,b._fullPathName, status)); + BufferID bufID = _pNonDocTab->getBufferByIndex(i); + Buffer * b = MainFileManager->getBufferByID(bufID); + int status = b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved); + tli->_tlfsLst.push_back(TaskLstFnStatus(otherView(), i, b->getFilePath(), status)); } } @@ -5776,15 +5511,31 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa // Menu _mainMenuHandle = ::GetMenu(_hSelf); + //Views _pDocTab = &_mainDocTab; _pEditView = &_mainEditView; + _pNonDocTab = &_subDocTab; + _pNonEditView = &_subEditView; + + _mainWindowStatus = WindowMainActive; + _activeView = MAIN_VIEW; const ScintillaViewParams & svp1 = pNppParam->getSVP(SCIV_PRIMARY); const ScintillaViewParams & svp2 = pNppParam->getSVP(SCIV_SECOND); _mainEditView.init(_hInst, hwnd); _subEditView.init(_hInst, hwnd); + _fileEditView.init(_hInst, hwnd); + + MainFileManager->init(this, &_fileEditView); //get it up and running asap. + int tabBarStatus = nppGUI._tabStatus; + _toReduceTabBar = ((tabBarStatus & TAB_REDUCE) != 0); + _docTabIconList.create(_toReduceTabBar?13:20, _hInst, docTabIconIDs, sizeof(docTabIconIDs)/sizeof(int)); + + _mainDocTab.init(_hInst, hwnd, &_mainEditView, &_docTabIconList); + _subDocTab.init(_hInst, hwnd, &_subEditView, &_docTabIconList); + _mainEditView.display(); _mainEditView.execute(SCI_MARKERSETALPHA, MARK_BOOKMARK, 70); @@ -5799,7 +5550,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa _invisibleEditView.init(_hInst, hwnd); _invisibleEditView.execute(SCI_SETUNDOCOLLECTION); _invisibleEditView.execute(SCI_EMPTYUNDOBUFFER); - _invisibleEditView.attatchDefaultDoc(0); + //_invisibleEditView.attachDefaultDoc(); // Configuration of 2 scintilla views _mainEditView.showMargin(ScintillaEditView::_SC_MARGE_LINENUMBER, svp1._lineNumberMarginShow); @@ -5847,15 +5598,6 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa _mainEditView.execute(SCI_SETZOOM, svp1._zoom); _subEditView.execute(SCI_SETZOOM, svp2._zoom); - int tabBarStatus = nppGUI._tabStatus; - _toReduceTabBar = ((tabBarStatus & TAB_REDUCE) != 0); - _docTabIconList.create(_toReduceTabBar?13:20, _hInst, docTabIconIDs, sizeof(docTabIconIDs)/sizeof(int)); - - _subDocTab.init(_hInst, hwnd, &_subEditView, &_docTabIconList); - - const char * str = _mainDocTab.init(_hInst, hwnd, &_mainEditView, &_docTabIconList); - setTitleWith(str); - TabBarPlus::doDragNDrop(true); if (_toReduceTabBar) @@ -6178,6 +5920,12 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa ContainerTabInfo & cti = dmd._containerTabInfo[i]; _dockingManager.setActiveTab(cti._cont, cti._activeTab); } + + //Load initial docs into doctab + loadBufferIntoView(_mainEditView.attachDefaultDoc(), MAIN_VIEW); + loadBufferIntoView(_subEditView.attachDefaultDoc(), SUB_VIEW); + MainFileManager->increaseDocNr(); //so next doc starts at 2 + ::SetFocus(_mainEditView.getHSelf()); result = TRUE; @@ -6209,8 +5957,13 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa { char name[256]; strcpy(name, (char *)lParam); - _mainEditView.removeUserLang(name); - _subEditView.removeUserLang(name); + //loop through buffers and reset the language (L_USER, "") if (L_USER, name) + Buffer * buf; + for(int i = 0; i < MainFileManager->getNrBuffers(); i++) { + buf = MainFileManager->getBufferByIndex(i); + if (buf->getLangType() == L_USER && !strcmp(buf->getUserDefineLangName(), name)) + buf->setLangType(L_USER, ""); + } return TRUE; } @@ -6220,8 +5973,13 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa char newName[256]; strcpy(oldName, (char *)lParam); strcpy(newName, (char *)wParam); - _mainEditView.renameUserLang(oldName, newName); - _subEditView.renameUserLang(oldName, newName); + //loop through buffers and reset the language (L_USER, newName) if (L_USER, oldName) + Buffer * buf; + for(int i = 0; i < MainFileManager->getNrBuffers(); i++) { + buf = MainFileManager->getBufferByIndex(i); + if (buf->getLangType() == L_USER && !strcmp(buf->getUserDefineLangName(), oldName)) + buf->setLangType(L_USER, newName); + } return TRUE; } @@ -6284,7 +6042,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa } else { - LangType lt = _pEditView->getCurrentDocType(); + LangType lt = _pEditView->getCurrentBuffer()->getLangType(); const char *ext = NppParameters::getInstance()->getLangExtFromLangType(lt); if (ext && ext[0]) @@ -6308,19 +6066,27 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case WM_DOOPEN: { - doOpen((const char *)lParam); + BufferID lastOpened = doOpen((const char *)lParam); + if (lastOpened != BUFFER_INVALID) { + switchToFile(lastOpened); + } } break; case NPPM_RELOADFILE: { - doReload((const char *)lParam, wParam != 0); + BufferID id = MainFileManager->getBufferFromName((const char *)lParam); + if (id != BUFFER_INVALID) + doReload(id, wParam != 0); } break; case NPPM_SWITCHTOFILE : { - return switchToFile((const char *)lParam); + BufferID id = MainFileManager->getBufferFromName((const char *)lParam); + if (id != BUFFER_INVALID) + return switchToFile(id); + return false; } case NPPM_SAVECURRENTFILE: @@ -6393,34 +6159,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case COPYDATA_FILENAMES : { CmdLineParams & cmdLineParams = pNppParam->getCmdLineParams(); - LangType lt = cmdLineParams._langType;//LangType(pCopyData->dwData & LASTBYTEMASK); - int ln = cmdLineParams._line2go; - int currentDocIndex = _pEditView->getCurrentDocIndex(); - int currentView = getCurrentView(); - - FileNameStringSplitter fnss((char *)pCopyData->lpData); - char *pFn = NULL; - for (int i = 0 ; i < fnss.size() ; i++) - { - pFn = (char *)fnss.getFileName(i); - int res = doOpen((const char *)pFn, cmdLineParams._isReadOnly); - if (res == OPEN_FAILURE) - continue; - if (lt != L_TXT) - { - _pEditView->setCurrentDocType(lt); - setLangStatus(lt); - checkLangsMenu(-1); - } - _pEditView->execute(SCI_GOTOLINE, ln-1); - } - - if (_isSaving == true) - { - switchEditViewTo(currentView); - setTitleWith(_pDocTab->activate(currentDocIndex)); - return true; - } + loadCommandlineParams((const char *)pCopyData->lpData, &cmdLineParams); break; } } @@ -6456,7 +6195,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa { char str[MAX_PATH]; // par defaut : NPPM_GETCURRENTDIRECTORY - char *fileStr = strcpy(str, _pEditView->getCurrentTitle()); + char *fileStr = strcpy(str, _pEditView->getCurrentBuffer()->getFilePath()); if (Message == NPPM_GETCURRENTDIRECTORY) PathRemoveFileSpec(str); @@ -6552,20 +6291,20 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case NPPM_GETCURRENTLANGTYPE : { - *((LangType *)lParam) = _pEditView->getCurrentDocType(); + *((LangType *)lParam) = _pEditView->getCurrentBuffer()->getLangType(); return TRUE; } case NPPM_SETCURRENTLANGTYPE : { - _pEditView->setCurrentDocType((LangType)lParam); + _pEditView->getCurrentBuffer()->setLangType((LangType)lParam); return TRUE; } case NPPM_GETNBOPENFILES : { - int nbDocPrimary = _mainEditView.getNbDoc(); - int nbDocSecond = _subEditView.getNbDoc(); + int nbDocPrimary = _mainDocTab.nbItem(); + int nbDocSecond = _subDocTab.nbItem(); if (lParam == ALL_OPEN_FILES) return nbDocPrimary + nbDocSecond; else if (lParam == PRIMARY_VIEW) @@ -6575,35 +6314,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa } case NPPM_GETOPENFILENAMESPRIMARY : - { - if (!wParam) return 0; - - char **fileNames = (char **)wParam; - size_t nbFileNames = lParam; - size_t i = 0; - - for ( ; i < nbFileNames ; i++) - { - strcpy(fileNames[i], _mainEditView.getBufferAt(i).getFileName()); - } - return i; - } - case NPPM_GETOPENFILENAMESSECOND : - { - if (!wParam) return 0; - - char **fileNames = (char **)wParam; - size_t nbFileNames = lParam; - size_t i = 0; - - for ( ; i < nbFileNames ; i++) - { - strcpy(fileNames[i], _subEditView.getBufferAt(i).getFileName()); - } - return i; - } - case NPPM_GETOPENFILENAMES : { if (!wParam) return 0; @@ -6612,13 +6323,21 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa int nbFileNames = lParam; int j = 0; - for (size_t i = 0 ; i < _mainEditView.getNbDoc() && j < nbFileNames ; i++) - { - strcpy(fileNames[j++], _mainEditView.getBufferAt(i).getFileName()); + if (Message != NPPM_GETOPENFILENAMESSECOND) { + for (int i = 0 ; i < _mainDocTab.nbItem() && j < nbFileNames ; i++) + { + BufferID id = _mainDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(id); + strcpy(fileNames[j++], buf->getFilePath()); + } } - for (size_t i = 0 ; i < _subEditView.getNbDoc() && j < nbFileNames ; i++) - { - strcpy(fileNames[j++], _subEditView.getBufferAt(i).getFileName()); + if (Message != NPPM_GETOPENFILENAMESPRIMARY) { + for (int i = 0 ; i < _subDocTab.nbItem() && j < nbFileNames ; i++) + { + BufferID id = _subDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(id); + strcpy(fileNames[j++], buf->getFilePath()); + } } return j; } @@ -6632,14 +6351,14 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa if (NppParameters::getInstance()->getNppGUI()._styleMRU) { tli->_currentIndex = 0; - std::sort(tli->_tlfsLst.begin(),tli->_tlfsLst.end(),SortTaskListPred(_mainEditView,_subEditView)); + std::sort(tli->_tlfsLst.begin(),tli->_tlfsLst.end(),SortTaskListPred(_mainDocTab,_subDocTab)); } else { for(int idx = 0; idx < (int)tli->_tlfsLst.size(); ++idx) { - if(tli->_tlfsLst[idx]._iView == getCurrentView() && - tli->_tlfsLst[idx]._docIndex == getCurrentEditView()->getCurrentDocIndex()) + if(tli->_tlfsLst[idx]._iView == currentView() && + tli->_tlfsLst[idx]._docIndex == _pDocTab->getCurrentTabIndex()) { tli->_currentIndex = idx; break; @@ -6668,8 +6387,8 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa { case APPCOMMAND_BROWSER_BACKWARD : case APPCOMMAND_BROWSER_FORWARD : - int nbDoc = _mainDocTab.isVisible()?_mainEditView.getNbDoc():0; - nbDoc += _subDocTab.isVisible()?_subEditView.getNbDoc():0; + int nbDoc = viewVisible(MAIN_VIEW)?_mainDocTab.nbItem():0; + nbDoc += viewVisible(SUB_VIEW)?_subDocTab.nbItem():0; if (nbDoc > 1) activateNextDoc((GET_APPCOMMAND_LPARAM(lParam) == APPCOMMAND_BROWSER_FORWARD)?dirDown:dirUp); _linkTriggered = true; @@ -6753,7 +6472,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa pSci->execute(SCI_GETTEXT, length, (LPARAM)buffer); // convert here - UniMode unicodeMode = pSci->getCurrentBuffer().getUnicodeMode(); + UniMode unicodeMode = pSci->getCurrentBuffer()->getUnicodeMode(); UnicodeConvertor.setEncoding(unicodeMode); length = UnicodeConvertor.convert(buffer, length-1); @@ -6809,13 +6528,8 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa // set new encoding if BOM was changed by other programms UniMode um = UnicodeConvertor.getEncoding(); - (pSci->getCurrentBuffer()).setUnicodeMode(um); - checkUnicodeMenuItems(um); - - // Override the code page if Unicode - if (um != uni8Bit) - _pEditView->execute(SCI_SETCODEPAGE, SC_CP_UTF8); - + (pSci->getCurrentBuffer())->setUnicodeMode(um); + (pSci->getCurrentBuffer())->setDirty(true); return um; } @@ -6823,7 +6537,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case NPPM_TRIGGERTABBARCONTEXTMENU: { // similar to NPPM_ACTIVEDOC - int whichView = ((wParam != MAIN_VIEW) && (wParam != SUB_VIEW))?getCurrentView():wParam; + int whichView = ((wParam != MAIN_VIEW) && (wParam != SUB_VIEW))?currentView():wParam; int index = lParam; switchEditViewTo(whichView); @@ -6972,15 +6686,15 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa { if (lParam == SUB_VIEW) { - if (!_subDocTab.isVisible()) + if (!viewVisible(SUB_VIEW)) return -1; - return _subEditView.getCurrentDocIndex(); + return _subDocTab.getCurrentTabIndex(); } else //MAIN_VIEW { - if (!_mainDocTab.isVisible()) + if (!viewVisible(MAIN_VIEW)) return -1; - return _mainEditView.getCurrentDocIndex(); + return _mainDocTab.getCurrentTabIndex(); } } @@ -7070,24 +6784,6 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa return TRUE; } - case NPPM_INTERNAL_DOCSWITCHOFF : - { - removeHideLinesBookmarks(); - return TRUE; - } - - case NPPM_INTERNAL_DOCSWITCHIN : - { - _hideLinesMarks.empty(); - - checkDocState(); - dynamicCheckMenuAndTB(); - setLangStatus(_pEditView->getCurrentDocType()); - updateStatusBar(); - reloadOnSwitchBack(); - return TRUE; - } - case NPPM_INTERNAL_ISTABBARREDUCED : { return _toReduceTabBar?TRUE:FALSE; @@ -7213,8 +6909,9 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case WM_UPDATESCINTILLAS: { - _mainEditView.defineDocType(_mainEditView.getCurrentDocType()); - _subEditView.defineDocType(_subEditView.getCurrentDocType()); + //reset styler for change in Stylers.xml + _mainEditView.defineDocType(_mainEditView.getCurrentBuffer()->getLangType()); + _subEditView.defineDocType(_mainEditView.getCurrentBuffer()->getLangType()); _mainEditView.performGlobalStyles(); _subEditView.performGlobalStyles(); @@ -7230,6 +6927,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa fullScreenToggle(); const NppGUI & nppgui = pNppParam->getNppGUI(); + _lastRecentFileList.setLock(true); if (_configStyleDlg.isCreated() && ::IsWindowVisible(_configStyleDlg.getHSelf())) _configStyleDlg.restoreGlobalOverrideValues(); @@ -7402,10 +7100,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case NPPM_MAKECURRENTBUFFERDIRTY : { - _pEditView->setCurrentDocState(true); - _pDocTab->updateCurrentTabItem(); - checkDocState(); - synchronise(); + _pEditView->getCurrentBuffer()->setDirty(true); return TRUE; } @@ -7445,8 +7140,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case NPPM_HIDETABBAR : { bool hide = (lParam != 0); - bool oldVal = _mainDocTab.setHideTabBarStatus(hide); - _subDocTab.setHideTabBarStatus(hide); + bool oldVal = DocTabView::setHideTabBarStatus(hide); ::SendMessage(_hSelf, WM_SIZE, 0, 0); NppGUI & nppGUI = (NppGUI &)((NppParameters::getInstance())->getNppGUI()); @@ -7489,9 +7183,8 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa */ case NPPM_INTERNAL_ISFOCUSEDTAB : { - ScintillaEditView *cv = getCurrentEditView(); - HWND pMainTB = (_mainDocTab.getView() == cv)?_mainDocTab.getHSelf():_subDocTab.getHSelf(); - return (HWND)lParam == pMainTB; + HWND hTabToTest = (currentView() == MAIN_VIEW)?_mainDocTab.getHSelf():_subDocTab.getHSelf(); + return (HWND)lParam == hTabToTest; } case NPPM_INTERNAL_GETMENU : @@ -7507,7 +7200,7 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa case WM_INITMENUPOPUP: { - _windowsMenu.initPopupMenu((HMENU)wParam, _pEditView); + _windowsMenu.initPopupMenu((HMENU)wParam, _pDocTab); return TRUE; } @@ -7542,39 +7235,40 @@ LRESULT Notepad_plus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa break; case WDT_SAVE: { - int origPos = _pEditView->getCurrentDocIndex(); - for (int i=0, n=nmdlg->nItems; iItems[i]); - fileSave(); + //loop through nmdlg->nItems, get index and save it + for (int i = 0; i < (int)nmdlg->nItems; i++) { + fileSave(_pDocTab->getBufferByIndex(i)); } - activateDoc(origPos); nmdlg->processed = TRUE; } break; case WDT_CLOSE: { - for (int i=0, n=nmdlg->nItems; inItems, get index and close it + for (int i = 0; i < (int)nmdlg->nItems; i++) { + fileClose(_pDocTab->getBufferByIndex(i), currentView()); + nmdlg->Items[i] = 0xFFFFFFFF; // indicate file was closed UINT pos = nmdlg->Items[i]; - activateDoc(pos); - if (!fileClose()) - break; - for (int j=i+1; jnItems; ++j) if (nmdlg->Items[j] > pos) --nmdlg->Items[j]; - nmdlg->Items[i] = 0xFFFFFFFF; // indicate file was closed } nmdlg->processed = TRUE; } break; case WDT_SORT: - _pEditView->arrangeBuffers(nmdlg->nItems, nmdlg->Items); - nmdlg->processed = TRUE; - for (int i = _pEditView->getNbDoc()-1 ; i >= 0 ; --i) - { - Buffer & docBuf = _pEditView->getBufferAt(i); - _pDocTab->updateTabItem(i, PathFindFileName(docBuf.getFileName())); + if (nmdlg->nItems != _pDocTab->nbItem()) //sanity check, if mismatch just abort + break; + //Collect all buffers + std::vector tempBufs; + for(int i = 0; i < (int)nmdlg->nItems; i++) { + tempBufs.push_back(_pDocTab->getBufferByIndex(i)); } - activateDoc(nmdlg->curSel); + //Reset buffers + for(int i = 0; i < (int)nmdlg->nItems; i++) { + _pDocTab->setBuffer(i, tempBufs[nmdlg->Items[i]]); + } + activateBuffer(_pDocTab->getBufferByIndex(_pDocTab->getCurrentTabIndex()), currentView()); break; } return TRUE; @@ -7795,22 +7489,28 @@ bool Notepad_plus::getIntegralDockingData(tTbData & dockData, int & iCont, bool void Notepad_plus::getCurrentOpenedFiles(Session & session) { - _pEditView->saveCurrentPos(); - session._activeView = getCurrentView(); - int currentDocIndex = session._activeMainIndex = _mainEditView.getCurrentDocIndex(); - //int currentDocIndex = _mainEditView.getCurrentDocIndex(); + _mainEditView.saveCurrentPos(); //save position so itll be correct in the session + _subEditView.saveCurrentPos(); //both views + session._activeView = currentView(); + session._activeMainIndex = _mainDocTab.getCurrentTabIndex(); + session._activeSubIndex = _subDocTab.getCurrentTabIndex(); - for (size_t i = 0 ; i < _mainEditView.getNbDoc() ; i++) + //Use _invisibleEditView to temporarily open documents to retrieve markers + Buffer * mainBuf = _mainEditView.getCurrentBuffer(); + Buffer * subBuf = _subEditView.getCurrentBuffer(); + + for (int i = 0 ; i < _mainDocTab.nbItem() ; i++) { - const Buffer & buf = _mainEditView.getBufferAt((size_t)i); - if (!Buffer::isUntitled(buf._fullPathName) && PathFileExists(buf._fullPathName)) + BufferID bufID = _mainDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(bufID); + if (!buf->isUntitled() && PathFileExists(buf->getFilePath())) { string languageName = getLangFromMenu( buf ); const char *langName = languageName.c_str(); - sessionFileInfo sfi(buf._fullPathName, langName, buf._pos); + sessionFileInfo sfi(buf->getFilePath(), langName, buf->getPosition(&_mainEditView)); - _mainEditView.activateDocAt(i); + _mainEditView.activateBuffer(buf->getID()); int maxLine = _mainEditView.execute(SCI_GETLINECOUNT); for (int j = 0 ; j < maxLine ; j++) { @@ -7822,21 +7522,19 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session) session._mainViewFiles.push_back(sfi); } } - _mainEditView.activateDocAt(currentDocIndex); - session._activeSubIndex = _subEditView.getCurrentDocIndex(); - currentDocIndex = _subEditView.getCurrentDocIndex(); - for (size_t i = 0 ; i < _subEditView.getNbDoc() ; i++) + for (int i = 0 ; i < _subDocTab.nbItem() ; i++) { - const Buffer & buf = _subEditView.getBufferAt((size_t)i); - if (PathFileExists(buf._fullPathName)) + BufferID bufID = _subDocTab.getBufferByIndex(i); + Buffer * buf = MainFileManager->getBufferByID(bufID); + if (!buf->isUntitled() && PathFileExists(buf->getFilePath())) { string languageName = getLangFromMenu( buf ); const char *langName = languageName.c_str(); - sessionFileInfo sfi(buf._fullPathName, langName, buf._pos); + sessionFileInfo sfi(buf->getFilePath(), langName, buf->getPosition(&_subEditView)); - _subEditView.activateDocAt(i); + _subEditView.activateBuffer(buf->getID()); int maxLine = _subEditView.execute(SCI_GETLINECOUNT); for (int j = 0 ; j < maxLine ; j++) { @@ -7848,7 +7546,9 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session) session._subViewFiles.push_back(sfi); } } - _subEditView.activateDocAt(currentDocIndex); + + _mainEditView.activateBuffer(mainBuf->getID()); //restore buffer + _subEditView.activateBuffer(subBuf->getID()); //restore buffer } bool Notepad_plus::fileLoadSession(const char *fn) @@ -8012,78 +7712,54 @@ void Notepad_plus::markSelectedText() //This function is destructive bool Notepad_plus::emergency() { const char * outdir = "C:\\N++RECOV"; - bool status = false; + bool filestatus = false; + bool dumpstatus = false; do { if (::CreateDirectory(outdir, NULL) == FALSE && ::GetLastError() != ERROR_ALREADY_EXISTS) { break; } - ScintillaEditView * viewToRecover = &_mainEditView; - status |= dumpFiles(viewToRecover, outdir, "Main"); - viewToRecover = &_subEditView; - status |= dumpFiles(viewToRecover, outdir, "Sub"); + filestatus = dumpFiles(outdir, "File"); +/* + HANDLE hProcess = ::GetCurrentProcess(); + DWORD processId = ::GetCurrentProcessId(); + char dumpFile[MAX_PATH]; + _snprintf(dumpFile, MAX_PATH, "%s\\NPP_DUMP.dmp", outdir); + HANDLE hFile = ::CreateFile(dumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == INVALID_HANDLE_VALUE) { + ::MessageBox(NULL, "Failed to write dump file!", dumpFile, MB_OK|MB_ICONWARNING); + } + BOOL ret = ::MiniDumpWriteDump(hProcess, processId, hFile, MiniDumpNormal, NULL, NULL, NULL); //might want to add exception info aswell + dumpstatus = (ret == TRUE); +*/ } while (false); + bool status = filestatus;// && dumpstatus; return status; } -bool Notepad_plus::dumpFiles(ScintillaEditView * viewToRecover, const char * outdir, const char * fileprefix) { +bool Notepad_plus::dumpFiles(const char * outdir, const char * fileprefix) { //start dumping unsaved files to recovery directory bool somethingsaved = false; bool somedirty = false; - size_t nrdocs = viewToRecover->getNbDoc(); - bool skipfirst = viewToRecover->getCurrentDocIndex() == 0; //if cur doc is first, dont do setdocpointer or itll be deleted char savePath[MAX_PATH] = {0}; - int bufferSize = 2048; - char dataBuffer[2048+1] = {0}; //not too bug of a buffer, we dont know how much we've got here - - FILE * dumpFile; - TextRange textRange; - textRange.lpstrText = dataBuffer; //rescue primary - for(size_t i = 0; i < nrdocs; i++) { - Buffer & docbuf = viewToRecover->getBufferAt(i); - if (!docbuf.isDirty()) //skip saved documents + for(int i = 0; i < MainFileManager->getNrBuffers(); i++) { + Buffer * docbuf = MainFileManager->getBufferByIndex(i); + if (!docbuf->isDirty()) //skip saved documents continue; else somedirty = true; - if (i != 0 || !skipfirst) - viewToRecover->execute(SCI_SETDOCPOINTER, 0, docbuf._doc); - - const char * unitext = ""; - if (docbuf.getUnicodeMode() != uni8Bit) - unitext = "_uni"; + const char * unitext = (docbuf->getUnicodeMode() != uni8Bit)?"_utf8":""; sprintf(savePath, "%s\\%s%03d%s.dump", outdir, fileprefix, i, unitext); - dumpFile = fopen(savePath, "wb"); - if (!dumpFile) { //cannot create file, this is bad - ::MessageBox(NULL, savePath, "Cannot dump file", MB_OK | MB_ICONWARNING); - continue; - } - //now it gets tricky, we have to have some allocated memory, we can only hope we have some - int size = viewToRecover->execute(SCI_GETLENGTH); - int saved = 0; - while(0 < size) { - if (size < bufferSize) { - bufferSize = size; //last piece of data smaller than buffer - } + bool res = MainFileManager->saveBuffer(docbuf->getID(), savePath); - textRange.chrg.cpMin = saved; - textRange.chrg.cpMax = saved + bufferSize; - viewToRecover->execute(SCI_GETTEXTRANGE, 0, (LPARAM)&textRange); - size_t res = fwrite(dataBuffer, bufferSize, 1, dumpFile); - if (!res) //FAILURE! - break; - saved += bufferSize; - size -= bufferSize; - } - - somethingsaved |= size==0; - fclose(dumpFile); + somethingsaved |= res; } return somethingsaved || !somedirty; @@ -8108,4 +7784,178 @@ void Notepad_plus::drawTabbarColoursFromStylerArray() TabBarPlus::setColour(stInact->_fgColor, TabBarPlus::inactiveText); if (stInact && stInact->_bgColor != -1) TabBarPlus::setColour(stInact->_bgColor, TabBarPlus::inactiveBg); -} \ No newline at end of file +} +void Notepad_plus::notifyBufferChanged(Buffer * buffer, int mask) { + NppParameters *pNppParam = NppParameters::getInstance(); + const NppGUI & nppGUI = pNppParam->getNppGUI(); + + _mainEditView.bufferUpdated(buffer, mask); + _subEditView.bufferUpdated(buffer, mask); + _mainDocTab.bufferUpdated(buffer, mask); + _subDocTab.bufferUpdated(buffer, mask); + + bool mainActive = (_mainEditView.getCurrentBuffer() == buffer); + bool subActive = (_subEditView.getCurrentBuffer() == buffer); + + //Only event that applies to non-active Buffers + if (mask & BufferChangeStatus) { //reload etc + bool didDialog = false; + switch(buffer->getStatus()) { + case DOC_UNNAMED: { //nothing todo + break; } + case DOC_REGULAR: { //nothing todo + break; } + case DOC_MODIFIED: { //ask for reloading + bool autoUpdate = (nppGUI._fileAutoDetection == cdAutoUpdate) || (nppGUI._fileAutoDetection == cdAutoUpdateGo2end); + if (!autoUpdate) { + didDialog = true; + if (doReloadOrNot(buffer->getFilePath()) != IDYES) + break; //abort + } + int index = _pDocTab->getIndexByBuffer(buffer->getID()); + int iView = currentView(); + if (index == -1) + iView = otherView(); + activateBuffer(buffer->getID(), iView); //activate the buffer in the first view possible + doReload(buffer->getID(), false); + if (nppGUI._fileAutoDetection == cdAutoUpdateGo2end || nppGUI._fileAutoDetection == cdGo2end) { + ScintillaEditView * pView = &_mainEditView; + if (iView==SUB_VIEW) { + pView = &_subEditView; + } + int line = pView->lastZeroBasedLineNumber(); + pView->gotoLine(line); + } + break; } + case DOC_DELETED: { //ask for keep + int index = _pDocTab->getIndexByBuffer(buffer->getID()); + int iView = currentView(); + if (index == -1) + iView = otherView(); + activateBuffer(buffer->getID(), iView); //activate the buffer in the first view possible + didDialog = true; + if (doCloseOrNot(buffer->getFilePath()) == IDNO) { + //close in both views, doing current view last since that has to remain opened + doClose(buffer->getID(), otherView()); + doClose(buffer->getID(), currentView()); + } + break; } + } + + if (didDialog) { + int curPos = _pEditView->execute(SCI_GETCURRENTPOS); + ::PostMessage(_pEditView->getHSelf(), WM_LBUTTONUP, 0, 0); + ::PostMessage(_pEditView->getHSelf(), SCI_SETSEL, curPos, curPos); + } + } + + if (!mainActive && !subActive) { + return; + } + + if (mask & (BufferChangeLanguage)) { + if (mainActive) + _autoCompleteMain.setLanguage(buffer->getLangType()); + if (subActive) + _autoCompleteSub.setLanguage(buffer->getLangType()); + } + + if ((currentView() == MAIN_VIEW) && !mainActive) + return; + + if ((currentView() == SUB_VIEW) && !subActive) + return; + + if (mask & (BufferChangeDirty|BufferChangeFilename)) { + checkDocState(); + setTitle(); + char dir[MAX_PATH]; + strcpy(dir, buffer->getFilePath()); + PathRemoveFileSpec(dir); + setWorkingDir(dir); + } + if (mask & (BufferChangeLanguage)) { + checkLangsMenu(-1); //let N++ do search for the item + setLangStatus(buffer->getLangType()); + if (_mainEditView.getCurrentBuffer() == buffer) + _autoCompleteMain.setLanguage(buffer->getLangType()); + else if (_subEditView.getCurrentBuffer() == buffer) + _autoCompleteSub.setLanguage(buffer->getLangType()); + } + if (mask & (BufferChangeFormat|BufferChangeLanguage|BufferChangeUnicode)) { + updateStatusBar(); + checkUnicodeMenuItems(buffer->getUnicodeMode()); + setUniModeText(buffer->getUnicodeMode()); + setDisplayFormat(buffer->getFormat()); + } + +} + +void Notepad_plus::notifyBufferActivated(BufferID bufid, int view) { + Buffer * buf = MainFileManager->getBufferByID(bufid); + buf->increaseRecentTag(); + + if (view == MAIN_VIEW) { + _autoCompleteMain.setLanguage(buf->getLangType()); + } else if (view == SUB_VIEW) { + _autoCompleteSub.setLanguage(buf->getLangType()); + } + + if (view != currentView()) { + return; //dont care if another view did something + } + + checkDocState(); + dynamicCheckMenuAndTB(); + setLangStatus(buf->getLangType()); + updateStatusBar(); + char dir[MAX_PATH]; + strcpy(dir, buf->getFilePath()); + PathRemoveFileSpec(dir); + setWorkingDir(dir); + setTitle(); + //Make sure the colors of the tab controls match + ::InvalidateRect(_mainDocTab.getHSelf(), NULL, FALSE); + ::InvalidateRect(_subDocTab.getHSelf(), NULL, FALSE); + + _linkTriggered = true; +} + +void Notepad_plus::loadCommandlineParams(const char * commandLine, CmdLineParams * pCmdParams) { + if (!commandLine || ! pCmdParams) + return; + + FileNameStringSplitter fnss(commandLine); + const char *pFn = NULL; + + LangType lt = pCmdParams->_langType;//LangType(pCopyData->dwData & LASTBYTEMASK); + int ln = pCmdParams->_line2go; + bool readOnly = pCmdParams->_isReadOnly; + + BufferID lastOpened = BUFFER_INVALID; + for (int i = 0 ; i < fnss.size() ; i++) + { + pFn = fnss.getFileName(i); + BufferID bufID = BUFFER_INVALID; + bool exists = (bufID = MainFileManager->getBufferFromName(pFn)) != BUFFER_INVALID; + if (!exists) { + bufID = doOpen(pFn, readOnly); + } + if (bufID == BUFFER_INVALID) //cannot open file + continue; + + lastOpened = bufID; + + if (ln != 0 || exists) { //we have to move the cursor manually + int iView = currentView(); //store view since fileswitch can cause it to change + switchToFile(bufID); //switch to the file. No deferred loading, but this way we can easily move the cursor to the right position + + _pEditView->getCurrentBuffer()->setLangType(lt); + _pEditView->execute(SCI_GOTOLINE, ln-1); + switchEditViewTo(iView); //restore view + } + } + if (lastOpened != BUFFER_INVALID) { + switchToFile(lastOpened); + } +} diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index 0565b88da..503ed6ba8 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -47,23 +47,34 @@ #include "DockingManager.h" #include "Process.h" #include "AutoCompletion.h" +#include "Buffer.h" #define NOTEPAD_PP_CLASS_NAME "Notepad++" - - #define MENU 0x01 #define TOOLBAR 0x02 -//#define WM_LOADFILEBYPATH WM_USER +enum FileTransferMode { + TransferClone = 0x01, + TransferMove = 0x02 +}; -const bool MODE_TRANSFER = true; -const bool MODE_CLONE = false; +enum WindowStatus { //bitwise mask + WindowMainActive = 0x01, + WindowSubActive = 0x02, + WindowBothActive = 0x03, //little helper shortcut + WindowUserActive = 0x04, + WindowMask = 0x07 +}; -const unsigned char DOCK_MASK = 1; -const unsigned char TWO_VIEWS_MASK = 2; +/* +//Plugins rely on #define's +enum Views { + MAIN_VIEW = 0x00, + SUB_VIEW = 0x01 +}; +*/ -const int blockSize = 128 * 1024 + 4; struct TaskListInfo; static TiXmlNode * searchDlgNode(TiXmlNode *node, const char *dlgTagName); @@ -76,12 +87,6 @@ struct iconLocator { : listIndex(iList), iconIndex(iIcon), iconLocation(iconLoc){}; }; -enum FileOpenStatus { - OPEN_FAILURE, - OPEN_SUCCESS, - OPEN_EXISTS -}; - class FileDialog; class Notepad_plus : public Window { @@ -97,7 +102,7 @@ public: return _className; }; - void setTitleWith(const char *filePath); + void setTitle(); void getTaskListInfo(TaskListInfo *tli); // For filtering the modeless Dialog message @@ -111,24 +116,29 @@ public: return false; }; - // fileOperation - int doOpen(const char *fileName, bool isReadOnly = false); - bool doSimpleOpen(const char *fileName); - bool doReload(const char *fileName, bool alert = true); - inline void fileNew(); +// fileOperations + //The doXXX functions apply to a single buffer and dont need to worry about views, with the excpetion of doClose, since closing one view doesnt have to mean the document is gone + BufferID doOpen(const char *fileName, bool isReadOnly = false); + bool doReload(BufferID id, bool alert = true); + bool doSave(BufferID, const char * filename, bool isSaveCopy = false); + void doClose(BufferID, int whichOne); + inline void fileNew(); void fileOpen(); inline bool fileReload(); - bool fileClose(); + bool fileClose(BufferID id = BUFFER_INVALID, int curView = -1); //use curView to override view to close from bool fileCloseAll(); bool fileCloseAllButCurrent(); - bool fileSave(); + bool fileSave(BufferID id = BUFFER_INVALID); bool fileSaveAll(); - bool fileSaveAs(bool isSaveCopy = false); + bool fileSaveAs(BufferID id = BUFFER_INVALID, bool isSaveCopy = false); - bool doSave(const char *filename, UniMode mode, bool isSaveCopy = false); - // end fileOperation + bool addBufferToView(BufferID id, int whichOne); + bool moveBuffer(BufferID id, int whereTo); //assumes whereFrom is otherView(whereTo) + bool switchToFile(BufferID buffer); //find buffer in active view then in other view. +// end fileOperations + bool isFileSession(const char * filename); void filePrint(bool showDialog); bool saveScintillaParams(bool whichOne); @@ -169,13 +179,15 @@ public: }; bool addCurrentMacro(); - bool switchToFile(const char *fileName); inline void loadLastSession(); bool loadSession(Session & session); winVer getWinVersion() const {return _winVersion;}; bool emergency(); + + void notifyBufferChanged(Buffer * buffer, int mask); private: + void loadCommandlineParams(const char * commandLine, CmdLineParams * pCmdParams); static const char _className[32]; char _nppPath[MAX_PATH]; Window *_pMainWindow; @@ -186,18 +198,18 @@ private: TiXmlNode *_nativeLang, *_toolIcons; - unsigned char _mainWindowStatus; - DocTabView _mainDocTab; DocTabView _subDocTab; DocTabView *_pDocTab; + DocTabView *_pNonDocTab; ScintillaEditView _subEditView; ScintillaEditView _mainEditView; - - ScintillaEditView _invisibleEditView; + ScintillaEditView _invisibleEditView; //for searches + ScintillaEditView _fileEditView; //for FileManager ScintillaEditView *_pEditView; + ScintillaEditView *_pNonEditView; SplitterContainer *_pMainSplitter; SplitterContainer _subSplitter; @@ -250,7 +262,6 @@ private: bool _linkTriggered; bool _isDocModifing; bool _isHotspotDblClicked; - bool _isSaving; //For Dynamic selection highlight CharacterRange _prevSelectedRange; @@ -338,15 +349,42 @@ private: void specialCmd(int id, int param); void command(int id); +//Document management + unsigned char _mainWindowStatus; //For 2 views and user dialog if docked + int _activeView; + //User dialog docking + void dockUserDlg(); + void undockUserDlg(); + + //View visibility + void showView(int whichOne); + bool viewVisible(int whichOne); + void hideView(int whichOne); void hideCurrentView(); + bool bothActive() { return (_mainWindowStatus & WindowBothActive) == WindowBothActive; }; + + int currentView(); + int otherView(); + int otherFromView(int whichOne); + bool canHideView(int whichOne); //true if view can safely be hidden (no open docs etc) + + int switchEditViewTo(int gid); //activate other view (set focus etc) + + void docGotoAnotherEditView(FileTransferMode mode); //TransferMode + + void loadBufferIntoView(BufferID id, int whichOne, bool dontClose = false); //Doesnt _activate_ the buffer + void removeBufferFromView(BufferID id, int whichOne); //Activates alternative of possible, or creates clean document if not clean already + + bool activateBuffer(BufferID id, int whichOne); //activate buffer in that view if found + void notifyBufferActivated(BufferID bufid, int view); +//END: Document management int doSaveOrNot(const char *fn) { char phrase[512] = "Save file \""; strcat(strcat(phrase, fn), "\" ?"); return ::MessageBox(_hSelf, phrase, "Save", MB_YESNOCANCEL | MB_ICONQUESTION | MB_APPLMODAL); }; - int doReloadOrNot(const char *fn) { char phrase[512] = "The file \""; strcat(strcat(phrase, fn), "\" is modified by another program. Reload this file?"); @@ -372,16 +410,9 @@ private: void checkSyncState(); void dropFiles(HDROP hdrop); void checkModifiedDocument(); - void reload(const char *fileName); - - void docGotoAnotherEditView(bool mode); - void dockUserDlg(); - void undockUserDlg(); void getMainClientRect(RECT & rc) const; - int switchEditViewTo(int gid); - void dynamicCheckMenuAndTB() const; void enableConvertMenuItems(formatType f) const { @@ -392,36 +423,10 @@ private: void checkUnicodeMenuItems(UniMode um) const; - int getCurrentView() const { - return (_pEditView == &_mainEditView)?MAIN_VIEW:SUB_VIEW; - }; - - int getNonCurrentView() const { - return (_pEditView == &_mainEditView)?SUB_VIEW:MAIN_VIEW; - }; - - DocTabView * getNonCurrentDocTab() { - return (_pDocTab == &_mainDocTab)?&_subDocTab:&_mainDocTab; - }; - - ScintillaEditView * getCurrentEditView() { - return (_pEditView == &_mainEditView)?&_mainEditView:&_subEditView; - }; - - ScintillaEditView * getNonCurrentEditView() { - return (_pEditView == &_mainEditView)?&_subEditView:&_mainEditView; - }; - - void synchronise(); - string getLangDesc(LangType langType, bool shortDesc = false); void setLangStatus(LangType langType){ _statusBar.setText(getLangDesc(langType).c_str(), STATUSBAR_DOC_TYPE); - if (_pEditView == &_mainEditView) - _autoCompleteMain.setLanguage(langType); - else - _autoCompleteSub.setLanguage(langType); }; void setDisplayFormat(formatType f) { @@ -462,12 +467,7 @@ private: void checkLangsMenu(int id) const ; void setLanguage(int id, LangType langType) { - if (_pEditView->setCurrentDocType(langType)) - { - _pEditView->foldAll(fold_uncollapse); - setLangStatus(langType); - checkLangsMenu(id); - } + _pEditView->getCurrentBuffer()->setLangType(langType); }; int getFolderMarginStyle() const { @@ -646,62 +646,6 @@ private: return line; }; - int hideLinesMarkPresent(int lineno) const { - LRESULT state = _pEditView->execute(SCI_MARKERGET, lineno); - if ((state & (1 << MARK_HIDELINESBEGIN)) != 0) - return MARK_HIDELINESBEGIN; - else if ((state & (1 << MARK_HIDELINESEND)) != 0) - return MARK_HIDELINESEND; - return 0; - }; - - void hideLinesMarkDelete(int lineno, int which) const { - _pEditView->execute(SCI_MARKERDELETE, lineno, which); - }; - - bool showLines(int lineno) const { - if (lineno == -1) - lineno = _pEditView->getCurrentLineNumber(); - int hideLinesMark = hideLinesMarkPresent(lineno); - if (!hideLinesMark) - return false; - - // - int start = 0; - int end = 0; - if (hideLinesMark == MARK_HIDELINESEND) - { - end = lineno; - int i = lineno - 1; - for ( ; i >= 0 ; i--) - { - if (_pEditView->execute(SCI_GETLINEVISIBLE, i)) - break; - hideLinesMarkDelete(i, MARK_HIDELINESBEGIN); - hideLinesMarkDelete(i, MARK_HIDELINESEND); - } - start = i; - } - else if (hideLinesMark == MARK_HIDELINESBEGIN) - { - long nbLine = _pEditView->lastZeroBasedLineNumber(); - start = lineno; - int i = lineno + 1; - for ( ; i < nbLine ; i++) - { - if (_pEditView->execute(SCI_GETLINEVISIBLE, i)) - break; - hideLinesMarkDelete(i, MARK_HIDELINESBEGIN); - hideLinesMarkDelete(i, MARK_HIDELINESEND); - } - end = i; - } - _pEditView->execute(SCI_SHOWLINES, start+1, end-1); - hideLinesMarkDelete(start, MARK_HIDELINESBEGIN); - hideLinesMarkDelete(end, MARK_HIDELINESEND); - return true; - }; - void findMatchingBracePos(int & braceAtCaret, int & braceOpposite); void braceMatch(); @@ -774,36 +718,27 @@ private: command( id ); } - string getLangFromMenu(Buffer buf) + string getLangFromMenu(const Buffer * buf) { int id; const char * userLangName; char menuLangName[32]; - id = (NppParameters::getInstance())->langTypeToCommandID( buf.getLangType() ); + id = (NppParameters::getInstance())->langTypeToCommandID( buf->getLangType() ); - if ( ( id != IDM_LANG_USER ) || !( buf.isUserDefineLangExt() ) ) + if ( ( id != IDM_LANG_USER ) || !( buf->isUserDefineLangExt() ) ) { ( ::GetMenuString( _mainMenuHandle, id, menuLangName, sizeof( menuLangName ), MF_BYCOMMAND ) ); userLangName = (char *)menuLangName; } else { - userLangName = buf.getUserDefineLangName(); + userLangName = buf->getUserDefineLangName(); } return userLangName; } - void removeHideLinesBookmarks() { - for (size_t i = 0 ; i < _hideLinesMarks.size() ; i++) - { - hideLinesMarkDelete(_hideLinesMarks[i].first, MARK_HIDELINESBEGIN); - hideLinesMarkDelete(_hideLinesMarks[i].second, MARK_HIDELINESEND); - } - }; - void setFileOpenSaveDlgFilters(FileDialog & fDlg); - void reloadOnSwitchBack(); void markSelectedText(); void markSelectedTextInc(bool enable); @@ -875,7 +810,7 @@ private: return true; }; - bool dumpFiles(ScintillaEditView * viewToRecover, const char * outdir, const char * fileprefix = ""); //helper func + bool dumpFiles(const char * outdir, const char * fileprefix = ""); //helper func void drawTabbarColoursFromStylerArray(); }; diff --git a/PowerEditor/src/Notepad_plus.rc b/PowerEditor/src/Notepad_plus.rc index 30aa4315d..96c378a80 100644 --- a/PowerEditor/src/Notepad_plus.rc +++ b/PowerEditor/src/Notepad_plus.rc @@ -383,6 +383,9 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Go to another view", IDM_VIEW_GOTO_ANOTHER_VIEW MENUITEM "Clone to another view", IDM_VIEW_CLONE_TO_ANOTHER_VIEW + MENUITEM "Activate main view" IDM_VIEW_SWITCHTO_MAIN + MENUITEM "Activate sub view" IDM_VIEW_SWITCHTO_SUB + MENUITEM SEPARATOR MENUITEM "Synchronize Vertical Scrolling", IDM_VIEW_SYNSCROLLV MENUITEM "Synchronize Horizontal Scrolling", IDM_VIEW_SYNSCROLLH MENUITEM SEPARATOR diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index d86f19d4e..a0db8422e 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -107,6 +107,10 @@ WinMenuKeyDefinition winKeyDefs[] = { //array of accelerator keys for all std me {VK_F2, IDM_SEARCH_NEXT_BOOKMARK, false, false, false, NULL}, {VK_F2, IDM_SEARCH_PREV_BOOKMARK, false, false, true, NULL}, {VK_NULL, IDM_SEARCH_CLEAR_BOOKMARKS, false, false, false, NULL}, + {VK_NULL, IDM_SEARCH_CUTMARKEDLINES, false, false, false, NULL}, + {VK_NULL, IDM_SEARCH_COPYMARKEDLINES, false, false, false, NULL}, + {VK_NULL, IDM_SEARCH_PASTEMARKEDLINES, false, false, false, NULL}, + {VK_NULL, IDM_SEARCH_DELETEMARKEDLINES, false, false, false, NULL}, {VK_F11, IDM_VIEW_FULLSCREENTOGGLE, false, false, false, NULL}, {VK_NULL, IDM_VIEW_ALWAYSONTOP, false, false, false, NULL}, @@ -145,6 +149,8 @@ WinMenuKeyDefinition winKeyDefs[] = { //array of accelerator keys for all std me {VK_NULL, IDM_VIEW_CLONE_TO_ANOTHER_VIEW, false, false, false, NULL}, {VK_NULL, IDM_VIEW_SYNSCROLLV, false, false, false, NULL}, {VK_NULL, IDM_VIEW_SYNSCROLLH, false, false, false, NULL}, + {VK_F7, IDM_VIEW_SWITCHTO_MAIN, false, false, false, NULL}, + {VK_F8, IDM_VIEW_SWITCHTO_SUB, false, false, false, NULL}, {VK_NULL, IDM_FORMAT_TODOS, false, false, false, NULL}, {VK_NULL, IDM_FORMAT_TOUNIX, false, false, false, NULL}, diff --git a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp index cf0f5619e..848dbe366 100644 --- a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp +++ b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp @@ -296,10 +296,10 @@ bool AutoCompletion::setLanguage(LangType language) { const char * AutoCompletion::getApiFileName() { if (_curLang == L_USER) { - Buffer & currentBuf = _pEditView->getCurrentBuffer(); - if (currentBuf.isUserDefineLangExt()) + Buffer * currentBuf = _pEditView->getCurrentBuffer(); + if (currentBuf->isUserDefineLangExt()) { - return currentBuf.getUserDefineLangName(); + return currentBuf->getUserDefineLangName(); } } diff --git a/PowerEditor/src/ScitillaComponent/Buffer.cpp b/PowerEditor/src/ScitillaComponent/Buffer.cpp index 9f46b1662..61171859a 100644 --- a/PowerEditor/src/ScitillaComponent/Buffer.cpp +++ b/PowerEditor/src/ScitillaComponent/Buffer.cpp @@ -1,7 +1,95 @@ #include "Buffer.h" +#include +#include +#include +#include "Scintilla.h" +#include "Parameters.h" + + +#include "Notepad_plus.h" +#include "ScintillaEditView.h" + +FileManager * FileManager::_pSelf = new FileManager(); + +const int blockSize = 128 * 1024 + 4; +const char UNTITLED_STR[] = "new "; + +// Ordre important!! Ne le changes pas! +//SC_EOL_CRLF (0), SC_EOL_CR (1), or SC_EOL_LF (2). + +const int CR = 0x0D; +const int LF = 0x0A; + +static bool isInList(const char *token, const char *list) { + if ((!token) || (!list)) + return false; + char word[64]; + int i = 0; + int j = 0; + for (; i <= int(strlen(list)) ; i++) + { + if ((list[i] == ' ')||(list[i] == '\0')) + { + if (j != 0) + { + word[j] = '\0'; + j = 0; + + if (!stricmp(token, word)) + return true; + } + } + else + { + word[j] = list[i]; + j++; + } + } + return false; +}; + +void Buffer::determinateFormat(char *data) { + _format = WIN_FORMAT; + size_t len = strlen(data); + for (size_t i = 0 ; i < len ; i++) + { + if (data[i] == CR) + { + if (data[i+1] == LF) + { + _format = WIN_FORMAT; + break; + } + else + { + _format = MAC_FORMAT; + break; + } + } + if (data[i] == LF) + { + _format = UNIX_FORMAT; + break; + } + } + + doNotify(BufferChangeFormat); + return; +}; + long Buffer::_recentTagCtr = 0; +void Buffer::updateTimeStamp() { + struct _stat buf; + time_t timeStamp = (_stat(_fullPathName, &buf)==0)?buf.st_mtime:0; + + if (timeStamp != _timeStamp) { + _timeStamp = timeStamp; + doNotify(BufferChangeTimestamp); + } +}; + // Set full path file name in buffer object, // and determinate its language by its extension. // If the ext is not in the list, the defaultLang passed as argument will be set. @@ -9,11 +97,13 @@ void Buffer::setFileName(const char *fn, LangType defaultLang) { NppParameters *pNppParamInst = NppParameters::getInstance(); strcpy(_fullPathName, fn); - if (PathFileExists(_fullPathName)) - { - // for _lang - char *ext = PathFindExtension(_fullPathName); - if (*ext == '.') ext += 1; + _fileName = PathFindFileName(_fullPathName); + + // for _lang + _lang = defaultLang; + char *ext = PathFindExtension(_fullPathName); + if (*ext == '.') { //extension found + ext += 1; // Define User Lang firstly const char *langName = NULL; @@ -24,27 +114,94 @@ void Buffer::setFileName(const char *fn, LangType defaultLang) } else // if it's not user lang, then check if it's supported lang { - _lang = getLangFromExt(ext); - if (_lang == L_TXT) - { - char *fileName = PathFindFileName(_fullPathName); - - if ((!_stricmp(fileName, "makefile")) || (!_stricmp(fileName, "GNUmakefile"))) - _lang = L_MAKEFILE; - else if (!_stricmp(fileName, "CmakeLists.txt")) - _lang = L_CMAKE; - } _userLangExt[0] = '\0'; - } - - // for _timeStamp - updatTimeStamp(); + _lang = getLangFromExt(ext); + } } - else // new doc + + if (_lang == defaultLang || _lang == L_TXT) //language can probably be refined { - _lang = defaultLang; - _timeStamp = 0; + if ((!_stricmp(_fileName, "makefile")) || (!_stricmp(_fileName, "GNUmakefile"))) + _lang = L_MAKEFILE; + else if (!_stricmp(_fileName, "CmakeLists.txt")) + _lang = L_CMAKE; } + + updateTimeStamp(); + + doNotify(BufferChangeFilename | BufferChangeLanguage | BufferChangeTimestamp); +} + +bool Buffer::checkFileState() { //returns true if the status has been changed (it can change into DOC_REGULAR too). false otherwise + struct _stat buf; + + if (_currentStatus == DOC_UNNAMED) //unsaved document cannot change by environment + return false; + + if (_currentStatus != DOC_DELETED && !PathFileExists(_fullPathName)) //document has been deleted + { + _currentStatus = DOC_DELETED; + _isFileReadOnly = false; + _timeStamp = 0; + doNotify(BufferChangeStatus | BufferChangeReadonly | BufferChangeTimestamp); + return true; + } else if (_currentStatus == DOC_DELETED && PathFileExists(_fullPathName)) { //document has returned from its grave + if (!_stat(_fullPathName, &buf)) + { + _isFileReadOnly = (bool)(!(buf.st_mode & _S_IWRITE)); + + _currentStatus = DOC_MODIFIED; + _timeStamp = buf.st_mtime; + doNotify(BufferChangeStatus | BufferChangeReadonly | BufferChangeTimestamp); + return true; + } + } + + if (!_stat(_fullPathName, &buf)) + { + _isFileReadOnly = (bool)(!(buf.st_mode & _S_IWRITE)); + + if (_timeStamp != buf.st_mtime) { + _currentStatus = DOC_MODIFIED; + _timeStamp = buf.st_mtime; + doNotify(BufferChangeStatus | BufferChangeReadonly | BufferChangeTimestamp); + return true; + } + + doNotify(BufferChangeReadonly | BufferChangeTimestamp); + return false; + } + return false; +} + +void Buffer::setPosition(const Position & pos, ScintillaEditView * identifier) { + int index = indexOfReference(identifier); + if (index == -1) + return; + _positions[index] = pos; +} + +Position & Buffer::getPosition(ScintillaEditView * identifier) { + int index = indexOfReference(identifier); + return _positions.at(index); +} + +void Buffer::setHeaderLineState(const std::vector & folds, ScintillaEditView * identifier) { + int index = indexOfReference(identifier); + if (index == -1) + return; + //deep copy + std::vector & local = _foldStates[index]; + local.clear(); + size_t size = folds.size(); + for(size_t i = 0; i < size; i++) { + local.push_back(folds[i]); + } +} + +std::vector & Buffer::getHeaderLineState(ScintillaEditView * identifier) { + int index = indexOfReference(identifier); + return _foldStates.at(index); } LangType Buffer::getLangFromExt(const char *ext) @@ -79,3 +236,303 @@ LangType Buffer::getLangFromExt(const char *ext) } return L_TXT; } + +Lang * Buffer::getCurrentLang() const { + NppParameters *pNppParam = NppParameters::getInstance(); + int i = 0; + Lang *l = pNppParam->getLangFromIndex(i++); + while (l) + { + if (l->_langID == _lang) + return l; + + l = pNppParam->getLangFromIndex(i++); + } + return NULL; +}; + +int Buffer::indexOfReference(ScintillaEditView * identifier) const { + int size = (int)_referees.size(); + for(int i = 0; i < size; i++) { + if (_referees[i] == identifier) + return i; + } + return -1; //not found +} + +int Buffer::addReference(ScintillaEditView * identifier) { + if (indexOfReference(identifier) != -1) + return _references; + _referees.push_back(identifier); + _positions.push_back(Position()); + _foldStates.push_back(std::vector()); + _references++; + return _references; +} + +int Buffer::removeReference(ScintillaEditView * identifier) { + int indexToPop = indexOfReference(identifier); + if (indexToPop == -1) + return _references; + _referees.erase(_referees.begin() + indexToPop); + _positions.erase(_positions.begin() + indexToPop); + _foldStates.erase(_foldStates.begin() + indexToPop); + _references--; + return _references; +} + +void Buffer::setHideLineChanged(bool isHide, int location) { + for(int i = 0; i < _references; i++) { + _referees.at(i)->notifyMarkers(this, isHide, location, (i == _references-1)); + } +} +//filemanager +FileManager::FileManager() : + _nextNewNumber(1), _nextBufferID(0), _pNotepadPlus(NULL), _nrBufs(0), _pscratchTilla(NULL) +{ +} + +void FileManager::init(Notepad_plus * pNotepadPlus, ScintillaEditView * pscratchTilla) +{ + _pNotepadPlus = pNotepadPlus; + _pscratchTilla = pscratchTilla; + _pscratchTilla->execute(SCI_SETUNDOCOLLECTION, false); //dont store any undo information + _scratchDocDefault = (Document)_pscratchTilla->execute(SCI_GETDOCPOINTER); + _pscratchTilla->execute(SCI_ADDREFDOCUMENT, 0, _scratchDocDefault); +} + +FileManager::~FileManager() { + //Release automatic with Scintilla destructor + //_pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, _scratchDocDefault); +} + +void FileManager::checkFilesystemChanges() { + for(size_t i = 0; i < _nrBufs; i++) { + if (_buffers[i]->checkFileState()){} //something has changed. Triggers update automatically + //_pNotepadPlus->notifyBufferChanged(_buffers[i]._id, _buffers[i]); + } +} + +int FileManager::getBufferIndexByID(BufferID id) { + for(size_t i = 0; i < _nrBufs; i++) { + if (_buffers[i]->_id == id) + return (int)i; + } + return -1; +} + +Buffer * FileManager::getBufferByIndex(int index) { + return _buffers.at(index); +} + +Buffer * FileManager::getBufferByID(BufferID id) { + return (Buffer*)id; + //return _buffers.at(getBufferIndexByID(id)); +} + +void FileManager::beNotifiedOfBufferChange(Buffer * theBuf, int mask) { + _pNotepadPlus->notifyBufferChanged(theBuf, mask); +}; + +void FileManager::addBufferReference(BufferID buffer, ScintillaEditView * identifier) { + Buffer * buf = getBufferByID(buffer); + buf->addReference(identifier); +} + +void FileManager::closeBuffer(BufferID id, ScintillaEditView * identifier) { + int index = getBufferIndexByID(id); + Buffer * buf = getBufferByIndex(index); + + int oldRefs = buf->_references; + int refs = buf->removeReference(identifier); + //if (oldRefs != refs) + // _pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, buf->_doc); //we can release the document for the reference of container (it has changed so it was a valid operation) + if (!refs) { //buffer can be deallocated + _pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, buf->_doc); //release for FileManager, Document is now gone + _buffers.erase(_buffers.begin() + index); + delete buf; + _nrBufs--; + } +} + +BufferID FileManager::loadFile(const char * filename, Document doc) { + if (doc == NULL) { + doc = (Document)_pscratchTilla->execute(SCI_CREATEDOCUMENT); + } + + Utf8_16_Read UnicodeConvertor; //declare here so we can get information after loading is done + if (loadFileData(doc, filename, &UnicodeConvertor)) { + Buffer * newBuf = new Buffer(this, _nextBufferID, doc, DOC_REGULAR, filename); + BufferID id = (BufferID) newBuf; + newBuf->_id = id; + _buffers.push_back(newBuf); + _nrBufs++; + Buffer * buf = _buffers.at(_nrBufs - 1); + + // 3 formats : WIN_FORMAT, UNIX_FORMAT and MAC_FORMAT + if (UnicodeConvertor.getNewBuf()) { + buf->determinateFormat(UnicodeConvertor.getNewBuf()); + } else { + buf->determinateFormat(""); + } + buf->setUnicodeMode(UnicodeConvertor.getEncoding()); + + //determine buffer properties + BufferID retval = _nextBufferID++; + return id; + } else { //failed loading, release document + _pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, doc); //Failure, so release document + return BUFFER_INVALID; + } +} + +bool FileManager::reloadBuffer(BufferID id) { + Buffer * buf = getBufferByID(id); + Document doc = buf->getDocument(); + Utf8_16_Read UnicodeConvertor; + return loadFileData(doc, buf->getFilePath(), &UnicodeConvertor); +} + +bool FileManager::saveBuffer(BufferID id, const char * filename, bool isCopy) { + Buffer * buffer = getBufferByID(id); + bool isHidden = false; + bool isSys = false; + DWORD attrib; + + if (PathFileExists(filename)) + { + attrib = ::GetFileAttributes(filename); + + if (attrib != INVALID_FILE_ATTRIBUTES) + { + isHidden = (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; + if (isHidden) + ::SetFileAttributes(filename, attrib & ~FILE_ATTRIBUTE_HIDDEN); + + isSys = (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; + if (isSys) + ::SetFileAttributes(filename, attrib & ~FILE_ATTRIBUTE_SYSTEM); + } + } + + UniMode mode = buffer->getUnicodeMode(); + if (mode == uniCookie) + mode = uni8Bit; //set the mode to ANSI to prevent converter from adding BOM and performing conversions, Scintilla's data can be copied directly + + Utf8_16_Write UnicodeConvertor; + UnicodeConvertor.setEncoding(mode); + + FILE *fp = UnicodeConvertor.fopen(filename, "wb"); + if (fp) + { + _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, buffer->_doc); //generate new document + + + char data[blockSize + 1]; + int lengthDoc = _pscratchTilla->getCurrentDocLen(); + for (int i = 0; i < lengthDoc; i += blockSize) + { + int grabSize = lengthDoc - i; + if (grabSize > blockSize) + grabSize = blockSize; + + _pscratchTilla->getText(data, i, i + grabSize); + UnicodeConvertor.fwrite(data, grabSize); + } + UnicodeConvertor.fclose(); + + if (isHidden) + ::SetFileAttributes(filename, attrib | FILE_ATTRIBUTE_HIDDEN); + + if (isSys) + ::SetFileAttributes(filename, attrib | FILE_ATTRIBUTE_SYSTEM); + + if (isCopy) { + _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault); + return true; //all done + } + + buffer->setFileName(filename); + buffer->setDirty(false); + buffer->setStatus(DOC_REGULAR); + _pscratchTilla->execute(SCI_SETSAVEPOINT); + _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault); + + return true; + } + return false; +} + +BufferID FileManager::newEmptyDocument() { + char newTitle[10]; + strcpy(newTitle, UNTITLED_STR); + itoa(_nextNewNumber, newTitle+4, 10); + _nextNewNumber++; + Document doc = (Document)_pscratchTilla->execute(SCI_CREATEDOCUMENT); //this already sets a reference for filemanager + Buffer * newBuf = new Buffer(this, _nextBufferID, doc, DOC_UNNAMED, newTitle); + BufferID id = (BufferID)newBuf; + newBuf->_id = id; + _buffers.push_back(newBuf); + _nrBufs++; + BufferID retval = _nextBufferID++; + return id; +} + +BufferID FileManager::bufferFromDocument(Document doc, bool dontIncrease) { + char newTitle[10]; + strcpy(newTitle, UNTITLED_STR); + itoa(_nextNewNumber, newTitle+4, 10); + _pscratchTilla->execute(SCI_ADDREFDOCUMENT, 0, doc); //set reference for FileManager + Buffer * newBuf = new Buffer(this, _nextBufferID, doc, DOC_UNNAMED, newTitle); + BufferID id = (BufferID)newBuf; + newBuf->_id = id; + _buffers.push_back(newBuf); + _nrBufs++; + BufferID retval = _nextBufferID; + if (!dontIncrease) + _nextBufferID++; + return id; +} + +bool FileManager::loadFileData(Document doc, const char * filename, Utf8_16_Read * UnicodeConvertor) { + const int blockSize = 128 * 1024; //128 kB + char data[blockSize]; + + FILE *fp = fopen(filename, "rb"); + if (!fp) + return false; + + //Setup scratchtilla for new filedata + _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, doc); + _pscratchTilla->execute(SCI_CLEARALL); + + size_t lenFile = 0; + size_t lenConvert = 0; //just in case conversion results in 0, but file not empty + do { + lenFile = fread(data, 1, blockSize, fp); + lenConvert = UnicodeConvertor->convert(data, lenFile); + _pscratchTilla->execute(SCI_ADDTEXT, lenConvert, (LPARAM)(UnicodeConvertor->getNewBuf())); + } while (lenFile > 0); + + fclose(fp); + + _pscratchTilla->execute(SCI_EMPTYUNDOBUFFER); + _pscratchTilla->execute(SCI_SETSAVEPOINT); + _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault); + return true; +} +BufferID FileManager::getBufferFromName(const char * name) { + for(size_t i = 0; i < _buffers.size(); i++) { + if (!strcmp(name, _buffers.at(i)->getFilePath())) + return _buffers.at(i)->getID(); + } + return BUFFER_INVALID; +} + +bool FileManager::createEmptyFile(const char * path) { + FILE * file = fopen(path, "wb"); + if (!file) + return false; + fclose(file); + return true; +} diff --git a/PowerEditor/src/ScitillaComponent/Buffer.h b/PowerEditor/src/ScitillaComponent/Buffer.h index 88ed05736..f311fea95 100644 --- a/PowerEditor/src/ScitillaComponent/Buffer.h +++ b/PowerEditor/src/ScitillaComponent/Buffer.h @@ -18,124 +18,128 @@ #ifndef BUFFER_H #define BUFFER_H -#include -#include -#include -#include "Scintilla.h" -#include "Parameters.h" +#include "Utf8_16.h" + +class Buffer; +typedef Buffer * BufferID; //each buffer has unique ID by which it can be retrieved +#define BUFFER_INVALID (BufferID)0 -const char UNTITLED_STR[] = "new "; typedef sptr_t Document; -// Ordre important!! Ne le changes pas! -//SC_EOL_CRLF (0), SC_EOL_CR (1), or SC_EOL_LF (2). +enum DocFileStatus{ + DOC_REGULAR = 0x01, //should not be combined with anything + DOC_UNNAMED = 0x02, //not saved (new ##) + DOC_DELETED = 0x04, //doesnt exist in environment anymore, but not DOC_UNNAMED + DOC_MODIFIED = 0x08 //File in environment has changed +}; - -const int CR = 0x0D; -const int LF = 0x0A; - -enum docFileStaus{NEW_DOC, FILE_DELETED, NO_PROBLEM, MODIFIED_FROM_OUTSIDE}; +enum BufferStatusInfo { + BufferChangeLanguage = 0x001, //Language was altered + BufferChangeDirty = 0x002, //Buffer has changed dirty state + BufferChangeFormat = 0x004, //EOL type was changed + BufferChangeUnicode = 0x008, //Unicode type was changed + BufferChangeReadonly = 0x010, //Readonly state was changed, can be both file and user + BufferChangeStatus = 0x020, //Filesystem Status has changed + BufferChangeTimestamp = 0x040, //Timestamp was changed + BufferChangeFilename = 0x080, //Filename was changed + BufferChangeRecentTag = 0x100, //Recent tag has changed + BufferChangeMask = 0x1FF //Mask: covers all changes +}; struct HeaderLineState { - HeaderLineState() : _headerLineNumber(0), _isCollapsed(false){}; - HeaderLineState(int lineNumber, bool isFoldUp) : _headerLineNumber(lineNumber), _isCollapsed(isFoldUp){}; + HeaderLineState() : _headerLineNumber(0), _isExpanded(true){}; + HeaderLineState(int lineNumber, bool isExpanded) : _headerLineNumber(lineNumber), _isExpanded(isExpanded){}; int _headerLineNumber; - bool _isCollapsed; + bool _isExpanded; }; -/* -struct Position -{ - int _firstVisibleLine; - int _startPos; - int _endPos; - int _xOffset; -}; -*/ -//#define USER_LANG_CURRENT "" + const int userLangNameMax = 16; -static bool isInList(const char *token, const char *list) { - if ((!token) || (!list)) - return false; - char word[64]; - int i = 0; - int j = 0; - for (; i <= int(strlen(list)) ; i++) - { - if ((list[i] == ' ')||(list[i] == '\0')) - { - if (j != 0) - { - word[j] = '\0'; - j = 0; - - if (!stricmp(token, word)) - return true; - } - } - else - { - word[j] = list[i]; - j++; - } - } - return false; +//File manager class maintains all buffers +class FileManager { +public: + void init(Notepad_plus * pNotepadPlus, ScintillaEditView * pscratchTilla); + + //void activateBuffer(int index); + void checkFilesystemChanges(); + + int getNrBuffers() { return _nrBufs; }; + int getBufferIndexByID(BufferID id); + Buffer * getBufferByIndex(int index); //generates exception if index is invalid + Buffer * getBufferByID(BufferID id); //generates exception if id is invalid + + void beNotifiedOfBufferChange(Buffer * theBuf, int mask); + + void closeBuffer(BufferID, ScintillaEditView * identifer); //called by Notepad++ + + void addBufferReference(BufferID id, ScintillaEditView * identifer); //called by Scintilla etc indirectly + + BufferID loadFile(const char * filename, Document doc = NULL); //ID == BUFFER_INVALID on failure. If Doc == NULL, a new file is created, otherwise data is loaded in given document + BufferID newEmptyDocument(); + BufferID bufferFromDocument(Document doc, bool dontIncrease = false); //create Buffer from existing Scintilla, used from new Scintillas. If dontIncrease = true, then the new document number isnt increased afterwards. usefull for temporary but neccesary docs + + BufferID getBufferFromName(const char * name); + + bool reloadBuffer(BufferID id); + bool saveBuffer(BufferID id, const char * filename, bool isCopy = false); + + bool createEmptyFile(const char * path); + + static FileManager * getInstance() {return _pSelf;}; + void destroyInstance() { delete _pSelf; }; + + void increaseDocNr() { _nextNewNumber++; }; +private: + FileManager(); + ~FileManager(); + static FileManager *_pSelf; + + Notepad_plus * _pNotepadPlus; + ScintillaEditView * _pscratchTilla; + Document _scratchDocDefault; + + int _nextNewNumber; + + std::vector _buffers; + BufferID _nextBufferID; + size_t _nrBufs; + + bool loadFileData(Document doc, const char * filename, Utf8_16_Read * UnicodeConvertor); }; +#define MainFileManager FileManager::getInstance() class Buffer { -friend class ScintillaEditView; -friend class Notepad_plus; +friend class FileManager; public : - Buffer(Document doc, const char *fileName) - : _isDirty(false), _doc(doc), _isReadOnly(false), _isSetReadOnly(false), _recentTag(-1) + //Loading a document: + //constructor with ID. + //Set a reference (pointer to a container mostly, like DocTabView or ScintillaEditView) + //Set the position manually if needed + //Load the document into Scintilla/add to TabBar + //The entire lifetime if the buffer, the Document has reference count of _atleast_ one + //Destructor makes sure its purged + Buffer(FileManager * pManager, BufferID id, Document doc, DocFileStatus type, const char *fileName) //type must be either DOC_REGULAR or DOC_UNNAMED + : _pManager(pManager), _id(id), _isDirty(false), _doc(doc), _isFileReadOnly(false), _isUserReadOnly(false), _recentTag(-1), _references(0), + _canNotify(false), _timeStamp(0), _needLexer(true) { NppParameters *pNppParamInst = NppParameters::getInstance(); const NewDocDefaultSettings & ndds = (pNppParamInst->getNppGUI()).getNewDocDefaultSettings(); _format = ndds._format; _unicodeMode = ndds._encoding; - _pos._firstVisibleLine = 0; - _pos._startPos = 0; - _pos._endPos = 0; - _pos._xOffset = 0; - _pos._scrollWidth = 1; setFileName(fileName, ndds._lang); - //_userLangExt[0] = '\0'; + updateTimeStamp(); + checkFileState(); + _currentStatus = type; + _isDirty = false; + _userLangExt[0] = 0; + if (type == DOC_UNNAMED) + _needLexer = false; //empty document, no styling + _canNotify = true; }; - Buffer(const Buffer & buf) : _isDirty(buf._isDirty), _doc(buf._doc), _lang(buf._lang), - _timeStamp(buf._timeStamp), _isReadOnly(buf._isReadOnly), _isSetReadOnly(buf._isSetReadOnly), _pos(buf._pos), - _format(buf._format),_unicodeMode(buf._unicodeMode), _foldState(buf._foldState), _recentTag(buf._recentTag), - _dontBotherMeAnymore(false), _reloadOnSwitchBack(false) - { - strcpy(_fullPathName, buf._fullPathName); - strcpy(_userLangExt, buf._userLangExt); - }; - - Buffer & operator=(const Buffer & buf) - { - if (this != &buf) - { - this->_isDirty = buf._isDirty; - this->_doc = buf._doc; - this->_lang = buf._lang; - this->_timeStamp = buf._timeStamp; - this->_isReadOnly = buf._isReadOnly; - this->_isSetReadOnly = buf._isSetReadOnly; - this->_pos = buf._pos; - this->_format = buf._format; - this->_unicodeMode = buf._unicodeMode; - this->_foldState = buf._foldState; - this->_recentTag = buf._recentTag; - - strcpy(this->_fullPathName, buf._fullPathName); - strcpy(this->_userLangExt, buf._userLangExt); - } - return *this; - } - LangType getLangFromExt(const char *ext); // this method 1. copies the file name @@ -143,150 +147,127 @@ public : // 3. gets the last modified time void setFileName(const char *fn, LangType defaultLang = L_TXT); - const char * getFileName() const {return _fullPathName;}; + const char * getFilePath() const { + return _fullPathName; + }; - void updatTimeStamp() { - struct _stat buf; - _timeStamp = (_stat(_fullPathName, &buf)==0)?buf.st_mtime:0; + const char * getFileName() const { return _fileName; }; + + BufferID getID() const { + return _id; }; void increaseRecentTag() { _recentTag = ++_recentTagCtr; - } + doNotify(BufferChangeRecentTag); + }; long getRecentTag() const { return _recentTag; - } - - docFileStaus checkFileState() { - if (isUntitled(_fullPathName)) - { - _isReadOnly = false; - return NEW_DOC; - } - if (!PathFileExists(_fullPathName)) - { - _isReadOnly = false; - return FILE_DELETED; - } - struct _stat buf; - if (!_stat(_fullPathName, &buf)) - { - _isReadOnly = (bool)(!(buf.st_mode & _S_IWRITE)); - - if (_timeStamp != buf.st_mtime) - return MODIFIED_FROM_OUTSIDE; - } - return NO_PROBLEM; }; - // to use this method with open and save - void checkIfReadOnlyFile() { - struct _stat buf; - if (!_stat(_fullPathName, &buf)) - { - _isReadOnly = (bool)(!(buf.st_mode & _S_IWRITE)); - } - }; + bool checkFileState(); bool isDirty() const { return _isDirty; }; bool isReadOnly() const { - return (_isReadOnly || _isSetReadOnly); - }; - - bool isSystemReadOnly() const { - return _isReadOnly; + return (_isUserReadOnly || _isFileReadOnly); }; - bool isUserReadOnly() const { - return _isSetReadOnly; + bool isUntitled() const { + return (_currentStatus == DOC_UNNAMED); + }; + + bool getFileReadOnly() const { + return _isFileReadOnly; }; - bool setReadOnly(bool ro) { - bool oldVal = _isSetReadOnly; - _isSetReadOnly = ro; - return oldVal; + void setFileReadOnly(bool ro) { + _isFileReadOnly = ro; + doNotify(BufferChangeReadonly); + }; + + bool getUserReadOnly() const { + return _isUserReadOnly; }; - + + void setUserReadOnly(bool ro) { + _isUserReadOnly = ro; + doNotify(BufferChangeReadonly); + }; + + formatType getFormat() const { + return _format; + }; + + void setFormat(formatType format) { + _format = format; + doNotify(BufferChangeFormat); + }; + + LangType getLangType() const { + return _lang; + }; + + void setLangType(LangType lang, const char * userLangName = "") { + if (lang == _lang && lang != L_USER) + return; + _lang = lang; + if (_lang == L_USER) { + strcpy(_userLangExt, userLangName); + } + _needLexer = true; //change of lang means lexern eeds updating + doNotify(BufferChangeLanguage); + }; + + UniMode getUnicodeMode() const { + return _unicodeMode; + }; + + void setUnicodeMode(UniMode mode) { + /*if ((_unicodeMode != mode) && + !((_unicodeMode == uni8Bit) && (mode == uniCookie)) && \ + !((_unicodeMode == uniCookie) && (mode == uni8Bit))) { + //this check excludes switch between Utf8-w/o bom and ANSI. However, that makes a change too + }*/ + _unicodeMode = mode; + //_isDirty = true; //set to dirty if change unicode mode + doNotify(BufferChangeUnicode | BufferChangeDirty); + }; + DocFileStatus getStatus() const { + return _currentStatus; + }; + time_t getTimeStamp() const { return _timeStamp; }; - void synchroniseWith(const Buffer & buf) { - _isDirty = buf.isDirty(); - _timeStamp = buf.getTimeStamp(); - }; - - // that is : the prefix of the string is "new " - static bool isUntitled(const char *str2Test) { - return (strncmp(str2Test, UNTITLED_STR, sizeof(UNTITLED_STR)-1) == 0); - } - - void setFormat(formatType format) { - _format = format; + Document getDocument() const { + return _doc; }; - void determinateFormat(char *data) { - size_t len = strlen(data); - for (size_t i = 0 ; i < len ; i++) - { - if (data[i] == CR) - { - if (data[i+1] == LF) - { - _format = WIN_FORMAT; - return; - } - else - { - _format = MAC_FORMAT; - return; - } - } - if (data[i] == LF) - { - _format = UNIX_FORMAT; - return; - } - } - _format = WIN_FORMAT; + void setDirty(bool dirty) { + _isDirty = dirty; + doNotify(BufferChangeDirty); }; -/* - void detectBin(char *data) { - size_t len = strlen(data); - const size_t lenMax = 2048; - size_t size2Detect = (len > lenMax)?lenMax:len; - for (size_t i = 0 ; i < size2Detect ; i++) - { - if (isNotPrintableChar(data[i])) - { - _isBinary = true; - break; - } - } - }; -*/ - formatType getFormat() const { - return _format; - }; + void setPosition(const Position & pos, ScintillaEditView * identifier); + Position & getPosition(ScintillaEditView * identifier); + + void setHeaderLineState(const std::vector & folds, ScintillaEditView * identifier); + std::vector & getHeaderLineState(ScintillaEditView * identifier); + + void determinateFormat(char *data); bool isUserDefineLangExt() const { return (_userLangExt[0] != '\0'); }; - const char * getUserDefineLangName() const {return _userLangExt;}; - - void setUnicodeMode(UniMode mode) { - if ((_unicodeMode != mode) && !((_unicodeMode == uni8Bit) && (mode == uniCookie)) && \ - !((_unicodeMode == uniCookie) && (mode == uni8Bit))) - _isDirty = true; - _unicodeMode = mode; + const char * getUserDefineLangName() const { + return _userLangExt; }; - UniMode getUnicodeMode() const {return _unicodeMode;}; const char * getCommentLineSymbol() const { Lang *l = getCurrentLang(); @@ -295,12 +276,14 @@ public : return l->_pCommentLineSymbol; }; + const char * getCommentStart() const { Lang *l = getCurrentLang(); if (!l) return NULL; return l->_pCommentStart; }; + const char * getCommentEnd() const { Lang *l = getCurrentLang(); if (!l) @@ -308,53 +291,61 @@ public : return l->_pCommentEnd; }; - const Position & getPosition() const { - return _pos; - }; + bool getNeedsLexing() const { + return _needLexer; + }; - LangType getLangType() const { - return _lang; - }; + void setNeedsLexing(bool lex) { + _needLexer = lex; + }; - void setPosition(const Position& pos) { - _pos = pos; - }; - - //bool isBin() const {return _isBinary;}; + //these two return reference count after operation + int addReference(ScintillaEditView * identifier); //if ID not registered, creates a new Position for that ID and new foldstate + int removeReference(ScintillaEditView * identifier); //reduces reference. If zero, Document is purged + void setHideLineChanged(bool isHide, int location); private : - bool _isDirty; - Document _doc; + FileManager * _pManager; + bool _canNotify; + int _references; //if no references file inaccessible, can be closed + BufferID _id; + + //document properties + Document _doc; //invariable LangType _lang; char _userLangExt[userLangNameMax]; // it's useful if only (_lang == L_USER) - - time_t _timeStamp; // 0 if it's a new doc - bool _isReadOnly; - bool _isSetReadOnly; - Position _pos; - char _fullPathName[MAX_PATH]; + bool _isDirty; formatType _format; UniMode _unicodeMode; - std::vector _foldState; + bool _isUserReadOnly; + bool _needLexer; //initially true + //these properties have to be duplicated because of multiple references + //All the vectors must have the same size at all times + std::vector< ScintillaEditView * > _referees; + std::vector< Position > _positions; + std::vector< std::vector > _foldStates; + + //Environment properties + DocFileStatus _currentStatus; + time_t _timeStamp; // 0 if it's a new doc + bool _isFileReadOnly; + char _fullPathName[MAX_PATH]; + char * _fileName; //points to filename part in _fullPathName + long _recentTag; static long _recentTagCtr; - //bool _isBinary; - bool _dontBotherMeAnymore; - bool _reloadOnSwitchBack; - Lang * getCurrentLang() const { - NppParameters *pNppParam = NppParameters::getInstance(); - int i = 0; - Lang *l = pNppParam->getLangFromIndex(i++); - while (l) - { - if (l->_langID == _lang) - return l; + void updateTimeStamp(); + Lang * getCurrentLang() const; - l = pNppParam->getLangFromIndex(i++); - } - return NULL; - }; + int indexOfReference(ScintillaEditView * identifier) const; + + void setStatus(DocFileStatus status) { + _currentStatus = status; + doNotify(BufferChangeStatus); + } + + void doNotify(int mask) { if (_canNotify) _pManager->beNotifiedOfBufferChange(this, mask); }; }; #endif //BUFFER_H diff --git a/PowerEditor/src/ScitillaComponent/DocTabView.cpp b/PowerEditor/src/ScitillaComponent/DocTabView.cpp index e1c6fb650..2d07c4507 100644 --- a/PowerEditor/src/ScitillaComponent/DocTabView.cpp +++ b/PowerEditor/src/ScitillaComponent/DocTabView.cpp @@ -24,155 +24,123 @@ #include #include -unsigned short DocTabView::_nbNewTitle = 0; +bool DocTabView::_hideTabBarStatus = false; +void DocTabView::addBuffer(BufferID buffer) { + if (buffer == BUFFER_INVALID) //valid only + return; + if (this->getIndexByBuffer(buffer) != -1) //no duplicates + return; + Buffer * buf = MainFileManager->getBufferByID(buffer); + TCITEM tie; + tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; -// return the index if fn is found in DocTabView -// otherwise -1 -int DocTabView::find(const char *fn) const -{ - return _pView->findDocIndexByName(fn); + int index = -1; + if (_hasImgLst) + index = 0; + tie.iImage = index; + tie.pszText = (LPSTR)buf->getFileName(); + tie.lParam = (LPARAM)buffer; + ::SendMessage(_hSelf, TCM_INSERTITEM, _nbItem++, reinterpret_cast(&tie)); + bufferUpdated(buf, BufferChangeMask); + + ::SendMessage(_hParent, WM_SIZE, 0, 0); } -char * DocTabView::newDocInit() -{ - // create the new entry for this doc - char * newTitle = _pView->attatchDefaultDoc(_nbNewTitle++); +void DocTabView::closeBuffer(BufferID buffer) { + int indexToClose = getIndexByBuffer(buffer); + deletItemAt(indexToClose); - // create a new (the first) sub tab then hightlight it - TabBar::insertAtEnd(newTitle); - return newTitle; + ::SendMessage(_hParent, WM_SIZE, 0, 0); } -const char * DocTabView::newDoc(const char *fn) -{ - char *completName; - if ((!fn) || (!strcmp(fn, ""))) - completName = _pView->createNewDoc(_nbNewTitle++); - else - completName = _pView->createNewDoc(fn); - // for the title of sub tab - fn = PathFindFileName(completName); - char fnConformToTab[MAX_PATH]; +bool DocTabView::activateBuffer(BufferID buffer) { + int indexToActivate = getIndexByBuffer(buffer); + if (indexToActivate == -1) + return false; //cannot activate + activateAt(indexToActivate); + return true; +} - for (int i = 0, j = 0 ; ; i++) - { - fnConformToTab[j++] = fn[i]; - if (fn[i] == '&') - fnConformToTab[j++] = '&'; - if (fn[i] == '\0') - break; +BufferID DocTabView::activeBuffer() { + int index = getCurrentTabIndex(); + return (BufferID)getBufferByIndex(index); +} + +BufferID DocTabView::findBufferByName(const char * fullfilename) { //-1 if not found, something else otherwise + TCITEM tie; + tie.lParam = -1; + tie.mask = TCIF_PARAM; + for(size_t i = 0; i < _nbItem; i++) { + ::SendMessage(_hSelf, TCM_GETITEM, i, reinterpret_cast(&tie)); + BufferID id = (BufferID)tie.lParam; + Buffer * buf = MainFileManager->getBufferByID(id); + if (!strcmp(fullfilename, buf->getFilePath())) { + return id; + } } - TabBar::insertAtEnd(fnConformToTab); - TabBar::activateAt(_nbItem - 1); - - if (_isMultiLine) - { - ::SendMessage(_hParent, WM_SIZE, 0, 0); - } - return (const char *)completName; + return BUFFER_INVALID; } -const char * DocTabView::newDoc(Buffer & buf) -{ - const char *completName = buf.getFileName(); - int i = _pView->addBuffer(buf); - _pView->activateDocAt(i); +int DocTabView::getIndexByBuffer(BufferID id) { + TCITEM tie; + tie.lParam = -1; + tie.mask = TCIF_PARAM; + for(int i = 0; i < (int)_nbItem; i++) { + ::SendMessage(_hSelf, TCM_GETITEM, i, reinterpret_cast(&tie)); + if ((BufferID)tie.lParam == id) + return i; + } + return -1; +} - // for the title of sub tab - TabBar::insertAtEnd(PathFindFileName(completName)); - TabBar::activateAt(_nbItem - 1); +BufferID DocTabView::getBufferByIndex(int index) { + TCITEM tie; + tie.lParam = -1; + tie.mask = TCIF_PARAM; + ::SendMessage(_hSelf, TCM_GETITEM, index, reinterpret_cast(&tie)); + + return (BufferID)tie.lParam; +} + +void DocTabView::bufferUpdated(Buffer * buffer, int mask) { + int index = getIndexByBuffer(buffer->getID()); + if (index == -1) + return; + + TCITEM tie; + tie.lParam = -1; + tie.mask = 0; - if (_isMultiLine) - { - ::SendMessage(_hParent, WM_SIZE, 0, 0); - } - return completName; -} -//! \brief this method activates the doc and the corresponding sub tab -//! \brief return the index of previeus current doc -char * DocTabView::activate(int index) -{ - TabBar::activateAt(index); - return _pView->activateDocAt(index); -} - -// this method updates the doc when user clicks a sub tab -// return Null if the user clicks on an active sub tab, -// otherwize the name of new activated doc -char * DocTabView::clickedUpdate() -{ - int indexClicked = int(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); - if (indexClicked == _pView->getCurrentDocIndex()) return NULL; - - return _pView->activateDocAt(indexClicked); -} - -const char * DocTabView::closeCurrentDoc() -{ - if (_nbItem == 1) - { - newDoc(); - closeDocAt(0); - } - else - { - int i2activate; - int i2close = _pView->closeCurrentDoc(i2activate); - - TabBar::deletItemAt(i2close); - - if (i2activate > 1) - TabBar::activateAt(i2activate-1); - - TabBar::activateAt(i2activate); + if (mask & BufferChangeReadonly || mask & BufferChangeDirty) { + tie.mask |= TCIF_IMAGE; + tie.iImage = buffer->isDirty()?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX; + if (buffer->isReadOnly()) { + tie.iImage = REDONLY_IMG_INDEX; + } } - if (_isMultiLine) - { - ::SendMessage(_hParent, WM_SIZE, 0, 0); + if (mask & BufferChangeFilename) { + tie.mask |= TCIF_TEXT; + tie.pszText = (LPSTR)buffer->getFileName(); } - return _pView->getCurrentTitle(); + ::SendMessage(_hSelf, TCM_SETITEM, index, reinterpret_cast(&tie)); + + ::SendMessage(_hParent, WM_SIZE, 0, 0); } -const char * DocTabView::closeAllDocs() -{ - _pView->removeAllUnusedDocs(); - TabBar::deletAllItem(); - _nbNewTitle = 0; - newDocInit(); - return _pView->getCurrentTitle(); -} - -void DocTabView::closeDocAt(int index2Close) -{ - _pView->closeDocAt(index2Close); - TabBar::deletItemAt(index2Close); -} - -void DocTabView::updateCurrentTabItem(const char *title) -{ - int currentIndex = TabCtrl_GetCurSel(_hSelf); - - updateTabItem(currentIndex, title); -} - -void DocTabView::updateTabItem(int index, const char *title) -{ - char str[MAX_PATH]; - TCITEM tie; - tie.mask = TCIF_TEXT | TCIF_IMAGE; - tie.pszText = str; - tie.cchTextMax = (sizeof(str)-1); - - TabCtrl_GetItem(_hSelf, index, &tie); - if ((title)&&(strcmp(title, ""))) - tie.pszText = (char *)title; - - bool isDirty = (_pView->getBufferAt(index)).isDirty();//isCurrentBufReadOnly(); - bool isReadOnly = (_pView->getBufferAt(index)).isReadOnly();//getCurrentDocStat(); - tie.iImage = isReadOnly?REDONLY_IMG_INDEX:(isDirty?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX); - TabCtrl_SetItem(_hSelf, index, &tie); +void DocTabView::setBuffer(int index, BufferID id) { + if (index < 0 || index >= (int)_nbItem) + return; + + TCITEM tie; + tie.lParam = (LPARAM)id; + tie.mask = TCIF_PARAM; + ::SendMessage(_hSelf, TCM_SETITEM, index, reinterpret_cast(&tie)); + + bufferUpdated(MainFileManager->getBufferByID(id), BufferChangeMask); //update tab, everything has changed + + ::SendMessage(_hParent, WM_SIZE, 0, 0); } diff --git a/PowerEditor/src/ScitillaComponent/DocTabView.h b/PowerEditor/src/ScitillaComponent/DocTabView.h index fdd5607b0..d22c89e36 100644 --- a/PowerEditor/src/ScitillaComponent/DocTabView.h +++ b/PowerEditor/src/ScitillaComponent/DocTabView.h @@ -29,47 +29,43 @@ const int REDONLY_IMG_INDEX = 2; class DocTabView : public TabBarPlus { public : - DocTabView():TabBarPlus(), _pView(NULL), _hideTabBarStatus(false){}; + DocTabView():TabBarPlus(), _pView(NULL) {}; virtual ~DocTabView(){}; virtual void destroy() { TabBarPlus::destroy(); }; - char * init(HINSTANCE hInst, HWND parent, ScintillaEditView *pView, IconList *pIconList = NULL) + void init(HINSTANCE hInst, HWND parent, ScintillaEditView * pView, IconList *pIconList = NULL) { TabBarPlus::init(hInst, parent); _pView = pView; - if (pIconList) TabBar::setImageList(pIconList->getHandle()); - return newDocInit(); + return; }; - char * newDocInit(); - int find(const char *) const; - char * activate(int index); - - const char * newDoc(const char *fn = NULL); - const char * newDoc(Buffer & buf); + void addBuffer(BufferID buffer); + void closeBuffer(BufferID buffer); + void bufferUpdated(Buffer * buffer, int mask); - char * clickedUpdate(); + bool activateBuffer(BufferID buffer); - const char * closeCurrentDoc(); - const char * closeAllDocs(); - void closeDocAt(int index); + BufferID activeBuffer(); + BufferID findBufferByName(const char * fullfilename); //-1 if not found, something else otherwise - //void setCurrentTabItem(const char *title, bool isDirty); - void updateCurrentTabItem(const char *title = NULL); - void updateTabItem(int index, const char *title = NULL); + int getIndexByBuffer(BufferID id); + BufferID getBufferByIndex(int index); - bool setHideTabBarStatus(bool hideOrNot){ + void setBuffer(int index, BufferID id); + + static bool setHideTabBarStatus(bool hideOrNot) { bool temp = _hideTabBarStatus; _hideTabBarStatus = hideOrNot; return temp; }; - bool getHideTabBarStatus() const { + static bool getHideTabBarStatus() { return _hideTabBarStatus; }; @@ -87,15 +83,10 @@ public : _pView->reSizeTo(rc); } }; - - const ScintillaEditView * getView() const { - return _pView; - }; private : - static unsigned short _nbNewTitle; ScintillaEditView *_pView; - bool _hideTabBarStatus; + static bool _hideTabBarStatus; }; #endif //DOCTABVIEW_H diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp index 156f71717..e43d34062 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp @@ -306,7 +306,7 @@ void FindReplaceDlg::create(int dialogID, bool isRTL) void FindReplaceDlg::updateCombos() { - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; HWND hReplaceCombo = ::GetDlgItem(_hSelf, IDREPLACEWITH); addText2Combo(getTextFromCombo(hReplaceCombo, isUnicode).c_str(), hReplaceCombo, isUnicode); @@ -521,7 +521,7 @@ BOOL CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lP { if ((_currentStatus == FIND_DLG) || (_currentStatus == REPLACE_DLG)) { - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; HWND hFindCombo = ::GetDlgItem(_hSelf, IDFINDWHAT); string str2Search = getTextFromCombo(hFindCombo, isUnicode); updateCombo(IDFINDWHAT); @@ -538,7 +538,7 @@ BOOL CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lP { if (_currentStatus == REPLACE_DLG) { - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; HWND hFindCombo = ::GetDlgItem(_hSelf, IDFINDWHAT); HWND hReplaceCombo = ::GetDlgItem(_hSelf, IDREPLACEWITH); string str2Search = getTextFromCombo(hFindCombo, isUnicode); @@ -915,7 +915,7 @@ bool FindReplaceDlg::processReplace(const char *txt2find, const char *txt2replac FindOption *pOptions = options?options:&_options; - if ((*_ppEditView)->getCurrentBuffer().isReadOnly()) return false; + if ((*_ppEditView)->getCurrentBuffer()->isReadOnly()) return false; int stringSizeFind = strlen(txt2find); int stringSizeReplace = strlen(txt2replace); @@ -950,12 +950,14 @@ bool FindReplaceDlg::processReplace(const char *txt2find, const char *txt2replac int replacedLen = (*_ppEditView)->execute(SCI_REPLACETARGETRE, stringSizeReplace, (LPARAM)pTextReplace); - if (!foundTextLen) - (*_ppEditView)->execute(SCI_SETSEL, start, start + replacedLen); + //if (!foundTextLen) + (*_ppEditView)->execute(SCI_SETSEL, start, start + replacedLen); } else { - (*_ppEditView)->execute(SCI_REPLACETARGET, stringSizeReplace, (LPARAM)pTextReplace); + int start = int((*_ppEditView)->execute(SCI_GETTARGETSTART)); + int replacedLen = (*_ppEditView)->execute(SCI_REPLACETARGET, stringSizeReplace, (LPARAM)pTextReplace); + (*_ppEditView)->execute(SCI_SETSEL, start, start + replacedLen); } } @@ -993,14 +995,14 @@ int FindReplaceDlg::processAll(ProcessOperation op, const char *txt2find, const if (!isCreated() && !txt2find) return nbReplaced; - if ((op == ProcessReplaceAll) && (*_ppEditView)->getCurrentBuffer().isReadOnly()) + if ((op == ProcessReplaceAll) && (*_ppEditView)->getCurrentBuffer()->isReadOnly()) return nbReplaced; if (!fileName) fileName = ""; FindOption *pOptions = opt?opt:&_options; - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; int stringSizeFind = 0; int stringSizeReplace = 0; @@ -1263,7 +1265,7 @@ void FindReplaceDlg::findAllIn(InWhat op) //HANDLE hEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, "findInFilesEvent"); if (!_pFinder) { - _pFinder = new Finder; + _pFinder = new Finder(); _pFinder->init(_hInst, _hSelf, _ppEditView); tTbData data = {0}; @@ -1281,6 +1283,7 @@ void FindReplaceDlg::findAllIn(InWhat op) ::SendMessage(_hParent, NPPM_DMMREGASDCKDLG, 0, (LPARAM)&data); _pFinder->_scintView.init(_hInst, _pFinder->getHSelf()); + _pFinder->setFinderReadOnly(true); _pFinder->_scintView.execute(SCI_SETCODEPAGE, SC_CP_UTF8); _pFinder->_scintView.execute(SCI_USEPOPUP, FALSE); @@ -1521,7 +1524,7 @@ BOOL CALLBACK FindIncrementDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM { case WM_COMMAND : { - bool isUnicode = (*(_pFRDlg->_ppEditView))->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*(_pFRDlg->_ppEditView))->getCurrentBuffer()->getUnicodeMode() != uni8Bit; switch (LOWORD(wParam)) { case IDCANCEL : diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h index fb1f5419a..38acde1c4 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h @@ -105,7 +105,9 @@ public: str += fileName; str += "]\n"; + setFinderReadOnly(false); _scintView.execute(SCI_APPENDTEXT, str.length(), (LPARAM)str.c_str()); + setFinderReadOnly(true); _lineCounter++; }; @@ -117,7 +119,9 @@ public: str += itoa(lineNb, lnb, 10); str += " : "; str += fi._foundLine; + setFinderReadOnly(false); _scintView.execute(SCI_APPENDTEXT, str.length(), (LPARAM)str.c_str()); + setFinderReadOnly(true); _lineCounter++; }; @@ -126,7 +130,9 @@ public: void removeAll() { _markedLine = -1; _foundInfos.clear(); + setFinderReadOnly(false); _scintView.execute(SCI_CLEARALL); + setFinderReadOnly(true); _lineCounter = 0; }; @@ -167,6 +173,10 @@ private: int _markedLine; InWhat _mode; size_t _lineCounter; + + void setFinderReadOnly(bool isReadOnly) { + _scintView.execute(SCI_SETREADONLY, isReadOnly); + }; }; //FindReplaceDialog: standard find/replace window @@ -248,10 +258,6 @@ public : addText2Combo(txt2find, ::GetDlgItem(_hSelf, IDFINDWHAT), isUTF8); } - void setFinderReadOnly(bool isReadOnly = true) { - _pFinder->_scintView.execute(SCI_SETREADONLY, isReadOnly); - }; - bool isFinderEmpty() const { return _pFinder->isEmpty(); }; @@ -291,7 +297,7 @@ public : }; string getText2search() const { - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; return getTextFromCombo(::GetDlgItem(_hSelf, IDFINDWHAT), isUnicode); }; @@ -363,7 +369,7 @@ private : void updateCombos(); void updateCombo(int comboID) { - bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit; + bool isUnicode = (*_ppEditView)->getCurrentBuffer()->getUnicodeMode() != uni8Bit; HWND hCombo = ::GetDlgItem(_hSelf, comboID); addText2Combo(getTextFromCombo(hCombo, isUnicode).c_str(), hCombo, isUnicode); }; diff --git a/PowerEditor/src/ScitillaComponent/Printer.cpp b/PowerEditor/src/ScitillaComponent/Printer.cpp index 425bc0a3d..2de3bf2a7 100644 --- a/PowerEditor/src/ScitillaComponent/Printer.cpp +++ b/PowerEditor/src/ScitillaComponent/Printer.cpp @@ -178,7 +178,7 @@ size_t Printer::doPrint(bool justDoIt) DOCINFO docInfo; docInfo.cbSize = sizeof(DOCINFO); - docInfo.lpszDocName = _pSEView->getCurrentTitle(); + docInfo.lpszDocName = _pSEView->getCurrentBuffer()->getFilePath(); docInfo.lpszOutput = NULL; if (::StartDoc(_pdlg.hDC, &docInfo) < 0) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index f95ba7e02..97e83a503 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -20,6 +20,7 @@ #include #include "ScintillaEditView.h" #include "Parameters.h" +#include "constant.h" // initialize the static variable @@ -193,6 +194,9 @@ void ScintillaEditView::init(HINSTANCE hInst, HWND hPere) _callWindowProc = CallWindowProcA; _scintillaDefaultProc = reinterpret_cast(::SetWindowLongA(_hSelf, GWL_WNDPROC, reinterpret_cast(scintillaStatic_Proc))); } + + //Get the startup document and make a buffer for it so it can be accessed like a file + //attachDefaultDoc(); //Let Notepad_plus do it } LRESULT ScintillaEditView::scintillaNew_Proc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) @@ -696,7 +700,6 @@ void ScintillaEditView::defineDocType(LangType typeDoc) } execute(SCI_STYLECLEARALL); - execute(SCI_CLEARDOCUMENTSTYLE); int iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_FOUND_STYLE); if (iFind != -1) @@ -735,7 +738,7 @@ void ScintillaEditView::defineDocType(LangType typeDoc) // Sinon y'aura un soucis de performance! if (isCJK()) { - if (getCurrentBuffer()._unicodeMode == uni8Bit) + if (getCurrentBuffer()->getUnicodeMode() == uni8Bit) execute(SCI_SETCODEPAGE, _codepage); } @@ -773,12 +776,13 @@ void ScintillaEditView::defineDocType(LangType typeDoc) case L_INI : setIniLexer(); break; - case L_USER : - if (_buffers[_currentIndex]._userLangExt[0]) - setUserLexer(_buffers[_currentIndex]._userLangExt); + case L_USER : { + const char * langExt = _currentBuffer->getUserDefineLangName(); + if (langExt[0]) + setUserLexer(langExt); else setUserLexer(); - break; + break; } case L_NFO : { @@ -937,44 +941,22 @@ void ScintillaEditView::defineDocType(LangType typeDoc) int bitsNeeded = execute(SCI_GETSTYLEBITSNEEDED); execute(SCI_SETSTYLEBITS, bitsNeeded); - - execute(SCI_COLOURISE, 0, -1); } -char * ScintillaEditView::attatchDefaultDoc(int nb) +BufferID ScintillaEditView::attachDefaultDoc() { - char title[10]; - char nb_str[4]; - strcat(strcpy(title, UNTITLED_STR), _itoa(nb, nb_str, 10)); - // get the doc pointer attached (by default) on the view Scintilla Document doc = execute(SCI_GETDOCPOINTER, 0, 0); + BufferID id = MainFileManager->bufferFromDocument(doc, false);//true); //keep counter on 1 + Buffer * buf = MainFileManager->getBufferByID(id); - // create the entry for our list - _buffers.push_back(Buffer(doc, title)); + MainFileManager->addBufferReference(id, this); //add a reference. Notepad only shows the buffer in tabbar - // set current index to 0 - _currentIndex = 0; + _currentBufferID = id; + _currentBuffer = buf; + bufferUpdated(buf, BufferChangeMask); //make sure everything is in sync with the buffer, since no reference exists - if (getCurrentBuffer()._unicodeMode != uni8Bit) - execute(SCI_SETCODEPAGE, SC_CP_UTF8); - - return _buffers[_currentIndex]._fullPathName; -} - - -int ScintillaEditView::findDocIndexByName(const char *fn) const -{ - int index = -1; - for (int i = 0 ; i < int(_buffers.size()) ; i++) - { - if (!stricmp(_buffers[i]._fullPathName, fn)) - { - index = i; - break; - } - } - return index; + return id; } void ScintillaEditView::saveCurrentPos() @@ -984,61 +966,66 @@ void ScintillaEditView::saveCurrentPos() int docLine = execute(SCI_DOCLINEFROMVISIBLE, displayedLine); //linenumber of the line displayed in the top //int offset = displayedLine - execute(SCI_VISIBLEFROMDOCLINE, docLine); //use this to calc offset of wrap. If no wrap this should be zero - Buffer & buf = _buffers[_currentIndex]; + Buffer * buf = MainFileManager->getBufferByID(_currentBufferID); + Position pos; // the correct visible line number - buf._pos._firstVisibleLine = docLine;//docLine - nbInvisibleLine; + pos._firstVisibleLine = docLine; + pos._startPos = static_cast(execute(SCI_GETSELECTIONSTART)); + pos._endPos = static_cast(execute(SCI_GETSELECTIONEND)); + pos._xOffset = static_cast(execute(SCI_GETXOFFSET)); + pos._selMode = execute(SCI_GETSELECTIONMODE); + pos._scrollWidth = execute(SCI_GETSCROLLWIDTH); - buf._pos._startPos = static_cast(execute(SCI_GETSELECTIONSTART)); - buf._pos._endPos = static_cast(execute(SCI_GETSELECTIONEND)); - buf._pos._xOffset = static_cast(execute(SCI_GETXOFFSET)); - buf._pos._selMode = execute(SCI_GETSELECTIONMODE); - buf._pos._scrollWidth = execute(SCI_GETSCROLLWIDTH); + buf->setPosition(pos, this); } void ScintillaEditView::restoreCurrentPos() { - _wrapRestoreNeeded = isWrap(); + Buffer * buf = MainFileManager->getBufferByID(_currentBufferID); + Position & pos = buf->getPosition(this); + execute(SCI_GOTOPOS, 0); //make sure first line visible by setting caret there, will scroll to top of document - Buffer & buf = _buffers[_currentIndex]; - - if (buf._pos._selMode == SC_SEL_RECTANGLE) - { - execute(SCI_SETSELECTIONMODE, buf._pos._selMode); + execute(SCI_SETSELECTIONMODE, pos._selMode); + execute(SCI_SETSELECTIONSTART, pos._startPos); + execute(SCI_SETSELECTIONEND, pos._endPos); + if (!isWrap()) { //only offset if not wrapping, otherwise the offset isnt needed at all + execute(SCI_SETSCROLLWIDTH, pos._scrollWidth); + execute(SCI_SETXOFFSET, pos._xOffset); } - execute(SCI_SETSELECTIONSTART, buf._pos._startPos); - execute(SCI_SETSELECTIONEND, buf._pos._endPos); - //int scrollWidth = execute(SCI_GETSCROLLWIDTH); - //execute(SCI_SETSCROLLWIDTH, scrollWidth); - execute(SCI_SETSCROLLWIDTH, buf._pos._scrollWidth); - - execute(SCI_SETXOFFSET, buf._pos._xOffset); - - // these 3 lines should be at the end so it works in wrap mode - int lineToShow = execute(SCI_VISIBLEFROMDOCLINE, buf._pos._firstVisibleLine); + int lineToShow = execute(SCI_VISIBLEFROMDOCLINE, pos._firstVisibleLine); scroll(0, lineToShow); } - - //! \brief this method activates the doc and the corresponding sub tab //! \brief return the index of previeus current doc -char * ScintillaEditView::activateDocAt(int index) +void ScintillaEditView::restyleBuffer() { + execute(SCI_CLEARDOCUMENTSTYLE); + execute(SCI_COLOURISE, 0, -1); + _currentBuffer->setNeedsLexing(false); +} + +void ScintillaEditView::styleChange() { + defineDocType(_currentBuffer->getLangType()); +} + +void ScintillaEditView::activateBuffer(BufferID buffer) { - ::SendMessage(_hParent, NPPM_INTERNAL_DOCSWITCHOFF, 0, (LPARAM)_hSelf); - - // To minimize the scroll width on each doc switch - //execute(SCI_SETSCROLLWIDTH, 1); + if (buffer == BUFFER_INVALID) + return; + if (buffer == _currentBuffer) + return; + Buffer * newBuf = MainFileManager->getBufferByID(buffer); // before activating another document, we get the current position // from the Scintilla view then save it to the current document saveCurrentPos(); - //Position & prevDocPos = _buffers[_currentIndex]._pos; - // get foldStateIOnfo of current doc + // get foldStateInfo of current doc std::vector lineStateVector; + int maxLine = execute(SCI_GETLINECOUNT); for (int line = 0; line < maxLine; line++) @@ -1052,76 +1039,85 @@ char * ScintillaEditView::activateDocAt(int index) } // put the state into the future ex buffer - _buffers[_currentIndex]._foldState = lineStateVector; - - // increase current doc ref count to 2 - execute(SCI_ADDREFDOCUMENT, 0, _buffers[_currentIndex]._doc); + _currentBuffer->setHeaderLineState(lineStateVector, this); + _currentBufferID = buffer; //the magical switch happens here + _currentBuffer = newBuf; // change the doc, this operation will decrease - // the ref count of old current doc to 1 - // then increase the new current doc to 2 - execute(SCI_SETDOCPOINTER, 0, _buffers[index]._doc); + // the ref count of old current doc and increase the one of the new doc. FileManager should manage the rest + // Note that the actual reference in the Buffer itself is NOT decreased, Notepad_plus does that if neccessary + execute(SCI_SETDOCPOINTER, 0, _currentBuffer->getDocument()); - // Important : to avoid the leak of memory - // Now keep the ref counter of new current doc as 1 - int refCtr = execute(SCI_RELEASEDOCUMENT, 0, _buffers[index]._doc); - - // NOW WE TAKE NEW DOC AND WE THROW OUT THE OLD ONE - _currentIndex = index; - - _buffers[_currentIndex].increaseRecentTag(); - // Due to execute(SCI_CLEARDOCUMENTSTYLE); in defineDocType() function // defineDocType() function should be called here, but not be after the fold info loop - defineDocType(_buffers[_currentIndex]._lang); + defineDocType(_currentBuffer->getLangType()); + + if (_currentBuffer->getNeedsLexing()) { + restyleBuffer(); + } // restore the collapsed info - int nbLineState = _buffers[_currentIndex]._foldState.size(); + std::vector & lineStateVectorNew = newBuf->getHeaderLineState(this); + int nbLineState = lineStateVectorNew.size(); for (int i = 0 ; i < nbLineState ; i++) { - HeaderLineState &hls = _buffers[_currentIndex]._foldState[i]; + HeaderLineState & hls = lineStateVectorNew.at(i); bool expanded = (execute(SCI_GETFOLDEXPANDED, hls._headerLineNumber) != 0); // set line to state folded - if (hls._isCollapsed && !expanded) - execute(SCI_TOGGLEFOLD, hls._headerLineNumber); - - if (!hls._isCollapsed && expanded) + if (hls._isExpanded != expanded) execute(SCI_TOGGLEFOLD, hls._headerLineNumber); } restoreCurrentPos(); - execute(SCI_SETEOLMODE, _buffers[_currentIndex]._format); - ::SendMessage(_hParent, NPPM_INTERNAL_DOCSWITCHIN, 0, (LPARAM)_hSelf); + bufferUpdated(_currentBuffer, (BufferChangeMask & ~BufferChangeLanguage)); //everything should be updated, but the language (which undoes some operations done here like folding) - return _buffers[_currentIndex]._fullPathName; + //setup line number margin + int numLines = execute(SCI_GETLINECOUNT); + + char numLineStr[32]; + itoa(numLines, numLineStr, 10); + int nbDigit = strlen(numLineStr); + + if (increaseMaxNbDigit(nbDigit)) + setLineNumberWidth(hasMarginShowed(ScintillaEditView::_SC_MARGE_LINENUMBER)); + + runMarkers(true, 0, true, false); + return; //all done } - -// this method creates a new doc ,and adds it into -// the end of the doc list and a last sub tab, then activate it -// it returns the name of this created doc (that's the current doc also) -char * ScintillaEditView::createNewDoc(const char *fn) -{ - Document newDoc = execute(SCI_CREATEDOCUMENT); - _buffers.push_back(Buffer(newDoc, fn)); - _buffers[_buffers.size()-1].checkIfReadOnlyFile(); - return activateDocAt(int(_buffers.size())-1); -} - -char * ScintillaEditView::createNewDoc(int nbNew) -{ - char title[10]; - char nb[4]; - strcat(strcpy(title, UNTITLED_STR), _itoa(nbNew, nb, 10)); - char * newTitle = createNewDoc(title); - if (getCurrentBuffer()._unicodeMode != uni8Bit) - execute(SCI_SETCODEPAGE, SC_CP_UTF8); - return newTitle; +void ScintillaEditView::bufferUpdated(Buffer * buffer, int mask) { + //actually only care about language and lexing etc + if (buffer == _currentBuffer) { + if (mask & BufferChangeLanguage) { + defineDocType(buffer->getLangType()); + foldAll(fold_uncollapse); + if (buffer->getNeedsLexing()) { + restyleBuffer(); + } + } + if (mask & BufferChangeFormat) { + execute(SCI_SETEOLMODE, _currentBuffer->getFormat()); + } + if (mask & BufferChangeReadonly) { + execute(SCI_SETREADONLY, _currentBuffer->isReadOnly()); + } + if (mask & BufferChangeUnicode) { + if (_currentBuffer->getUnicodeMode() == uni8Bit) { //either 0 or CJK codepage + if (isCJK()) { + execute(SCI_SETCODEPAGE, _codepage); //you may also want to set charsets here, not yet implemented + } else { + execute(SCI_SETCODEPAGE, 0); + } + } else { //CP UTF8 for all unicode + execute(SCI_SETCODEPAGE, SC_CP_UTF8); + } + } + } } void ScintillaEditView::collapse(int level2Collapse, bool mode) { - execute(SCI_COLOURISE, 0, -1); + execute(SCI_COLOURISE, 0, -1); //TODO: is this needed? int maxLine = execute(SCI_GETLINECOUNT); for (int line = 0; line < maxLine; line++) @@ -1135,7 +1131,8 @@ void ScintillaEditView::collapse(int level2Collapse, bool mode) execute(SCI_TOGGLEFOLD, line); } } - //recalcHorizontalScrollbar(); //Update scrollbar after folding + + runMarkers(true, 0, true, false); } void ScintillaEditView::foldCurrentPos(bool mode) @@ -1157,7 +1154,6 @@ void ScintillaEditView::foldCurrentPos(bool mode) if ((execute(SCI_GETFOLDEXPANDED, headerLine) != 0) != mode) execute(SCI_TOGGLEFOLD, headerLine); - //recalcHorizontalScrollbar(); //Update scrollbar after folding } void ScintillaEditView::foldAll(bool mode) @@ -1172,92 +1168,6 @@ void ScintillaEditView::foldAll(bool mode) if ((execute(SCI_GETFOLDEXPANDED, line) != 0) != mode) execute(SCI_TOGGLEFOLD, line); } - //recalcHorizontalScrollbar(); //Update scrollbar after folding -} - -// return the index to close then (argument) the index to activate -int ScintillaEditView::closeCurrentDoc(int & i2Activate) -{ - int oldCurrent = _currentIndex; - - //Position & prevDocPos = _buffers[_currentIndex]._pos; - - // if the file 2 delete is the last one - if (_currentIndex == int(_buffers.size()) - 1) - { - // if current index is 0, ie. the current is the only one - if (!_currentIndex) - { - _currentIndex = 0; - } - // the current is NOT the only one and it is the last one, - // we set it to the index which precedes it - else - _currentIndex -= 1; - } - // else the next current index will be the same, - // we do nothing - - // get the iterator and calculate its position with the old current index value - buf_vec_t::iterator posIt = _buffers.begin() + oldCurrent; - - // erase the position given document from our list - _buffers.erase(posIt); - - // set another document, so the ref count of old active document owned - // by Scintilla view will be decreased to 0 by SCI_SETDOCPOINTER message - // then increase the new current doc to 2 - execute(SCI_SETDOCPOINTER, 0, _buffers[_currentIndex]._doc); - - // Important : to avoid the leak of memory - // Now keep the ref counter of new current doc as 1 - execute(SCI_RELEASEDOCUMENT, 0, _buffers[_currentIndex]._doc); - - defineDocType(_buffers[_currentIndex]._lang); - restoreCurrentPos(); - - // restore the collapsed info - int nbLineState = _buffers[_currentIndex]._foldState.size(); - for (int i = 0 ; i < nbLineState ; i++) - { - HeaderLineState &hls = _buffers[_currentIndex]._foldState[i]; - bool expanded = (execute(SCI_GETFOLDEXPANDED, hls._headerLineNumber) != 0); - // set line to state folded - if (hls._isCollapsed && !expanded) - execute(SCI_TOGGLEFOLD, hls._headerLineNumber); - - if (!hls._isCollapsed && expanded) - execute(SCI_TOGGLEFOLD, hls._headerLineNumber); - } - - i2Activate = _currentIndex; - - return oldCurrent; -} - -void ScintillaEditView::closeDocAt(int i2Close) -{ - execute(SCI_RELEASEDOCUMENT, 0, _buffers[i2Close]._doc); - - // get the iterator and calculate its position with the old current index value - buf_vec_t::iterator posIt = _buffers.begin() + i2Close; - - // erase the position given document from our list - _buffers.erase(posIt); - - _currentIndex -= (i2Close < _currentIndex)?1:0; -} - -void ScintillaEditView::removeAllUnusedDocs() -{ - // unreference all docs from list of Scintilla - // by sending SCI_RELEASEDOCUMENT message - for (int i = 0 ; i < int(_buffers.size()) ; i++) - if (i != _currentIndex) - execute(SCI_RELEASEDOCUMENT, 0, _buffers[i]._doc); - - // remove all docs except the current doc from list - _buffers.clear(); } void ScintillaEditView::getText(char *dest, int start, int end) const @@ -1300,9 +1210,9 @@ void ScintillaEditView::marginClick(int position, int modifiers) { // Toggle this line execute(SCI_TOGGLEFOLD, lineClick, 0); + runMarkers(true, lineClick, true, false); } } - //recalcHorizontalScrollbar(); //Update scrollbar after folding } void ScintillaEditView::expand(int &line, bool doExpand, bool force, int visLevels, int level) @@ -1356,7 +1266,8 @@ void ScintillaEditView::expand(int &line, bool doExpand, bool force, int visLeve line++; } } - //recalcHorizontalScrollbar(); //Update scrollbar after folding + + runMarkers(true, 0, true, false); } void ScintillaEditView::performGlobalStyles() @@ -1486,7 +1397,7 @@ const char * ScintillaEditView::getCompleteKeywordList(std::string & kwl, LangTy void ScintillaEditView::convertSelectedTextTo(bool Case) { unsigned int codepage = _codepage; - UniMode um = getCurrentBuffer().getUnicodeMode(); + UniMode um = getCurrentBuffer()->getUnicodeMode(); if (um != uni8Bit) codepage = CP_UTF8; @@ -1571,30 +1482,6 @@ bool ScintillaEditView::expandWordSelection() return false; } - -void ScintillaEditView::arrangeBuffers(UINT nItems, UINT *items) { - // Do nothing if item size mismatches - if (nItems != getNbDoc()) - return; - int ncurpos = getCurrentDocIndex(); - int newpos = 0; - UINT i; - buf_vec_t tmp; - for (i=0; i= strLen) return NULL; @@ -1793,9 +1680,9 @@ void ScintillaEditView::columnReplace(const ColumnModeInfo & cmi, const char ch) void ScintillaEditView::foldChanged(int line, int levelNow, int levelPrev) { - if (levelNow & SC_FOLDLEVELHEADERFLAG) + if (levelNow & SC_FOLDLEVELHEADERFLAG) //line can be folded { - if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) + if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) //but previously couldnt { // Adding a fold point. execute(SCI_SETFOLDEXPANDED, line, 1); @@ -1821,3 +1708,175 @@ void ScintillaEditView::foldChanged(int line, int levelNow, int levelPrev) execute(SCI_SHOWLINES, line, line); } } + +void ScintillaEditView::hideLines() { + //Folding can screw up hide lines badly if it unfolds a hidden section. + //Adding runMarkers(hide, foldstart) directly (folding on single document) can help + + //Special func on buffer. If markers are added, create notification with location of start, and hide bool set to true + int startLine = execute(SCI_LINEFROMPOSITION, execute(SCI_GETSELECTIONSTART)); + int endLine = execute(SCI_LINEFROMPOSITION, execute(SCI_GETSELECTIONEND)); + //perform range check: cannot hide very first and very last lines + //Offset them one off the edges, and then check if they are within the reasonable + int nrLines = execute(SCI_GETLINECOUNT); + if (nrLines < 3) + return; //cannot possibly hide anything + if (!startLine) + startLine++; + if (endLine == (nrLines-1)) + endLine--; + + if (startLine > endLine) + return; //tried to hide line at edge + + //Hide the lines. We add marks on the outside of the hidden section and hide the lines + //execute(SCI_HIDELINES, startLine, endLine); + //Add markers + execute(SCI_MARKERADD, startLine-1, MARK_HIDELINESBEGIN); + execute(SCI_MARKERADD, endLine+1, MARK_HIDELINESEND); + + //remove any markers in between + int scope = 0; + for(int i = startLine; i <= endLine; i++) { + int state = execute(SCI_MARKERGET, i); + bool closePresent = ((state & (1 << MARK_HIDELINESEND)) != 0); //check close first, then open, since close closes scope + bool openPresent = ((state & (1 << MARK_HIDELINESBEGIN)) != 0); + if (closePresent) { + execute(SCI_MARKERDELETE, i, MARK_HIDELINESEND); + if (scope > 0) scope--; + } + if (openPresent) { + execute(SCI_MARKERDELETE, i, MARK_HIDELINESBEGIN); + scope++; + } + } + if (scope != 0) { //something went wrong + //Someone managed to make overlapping hidelines sections. + //We cant do anything since this isnt supposed to happen + } + + _currentBuffer->setHideLineChanged(true, startLine-1); +} + +bool ScintillaEditView::markerMarginClick(int lineNumber) { + + int state = execute(SCI_MARKERGET, lineNumber); + bool openPresent = ((state & (1 << MARK_HIDELINESBEGIN)) != 0); + bool closePresent = ((state & (1 << MARK_HIDELINESEND)) != 0); + + if (!openPresent && !closePresent) + return false; + + //Special func on buffer. First call show with location of opening marker. Then remove the marker manually + if (openPresent) { + _currentBuffer->setHideLineChanged(false, lineNumber); + } + if (closePresent) { + openPresent = false; + for(lineNumber--; lineNumber >= 0 && !openPresent; lineNumber--) { + state = execute(SCI_MARKERGET, lineNumber); + openPresent = ((state & (1 << MARK_HIDELINESBEGIN)) != 0); + } + if (openPresent) { + _currentBuffer->setHideLineChanged(false, lineNumber); + } + } + + return true; +} + +void ScintillaEditView::notifyMarkers(Buffer * buf, bool isHide, int location, bool del) { + if (buf != _currentBuffer) //if not visible buffer dont do a thing + return; + runMarkers(isHide, location, false, del); +} +//Run through full document. When switching in or opening folding +//hide is false only when user click on margin +void ScintillaEditView::runMarkers(bool doHide, int searchStart, bool endOfDoc, bool doDelete) { + //Removes markers if opening + /* + AllLines = (start,ENDOFDOCUMENT) + Hide: + Run through all lines. + Find open hiding marker: + set hiding start + Find closing: + if (hiding): + Hide lines between now and start + if (endOfDoc = false) + return + else + search for other hidden sections + + Show: + Run through all lines + Find open hiding marker + set last start + Find closing: + Show from last start. Stop. + Find closed folding header: + Show from last start to folding header + Skip to LASTCHILD + Set last start to lastchild + */ + int maxLines = execute(SCI_GETLINECOUNT); + if (doHide) { + int startHiding = searchStart; + bool isInSection = false; + for(int i = searchStart; i < maxLines; i++) { + int state = execute(SCI_MARKERGET, i); + if ( ((state & (1 << MARK_HIDELINESEND)) != 0) ) { + if (isInSection) { + execute(SCI_HIDELINES, startHiding, i-1); + if (!endOfDoc) { + return; //done, only single section requested + } //otherwise keep going + } + isInSection = false; + } + if ( ((state & (1 << MARK_HIDELINESBEGIN)) != 0) ) { + isInSection = true; + startHiding = i+1; + } + + } + } else { + int startShowing = searchStart; + bool isInSection = false; + for(int i = searchStart; i < maxLines; i++) { + int state = execute(SCI_MARKERGET, i); + if ( ((state & (1 << MARK_HIDELINESEND)) != 0) ) { + if (doDelete) + execute(SCI_MARKERDELETE, i, MARK_HIDELINESEND); + if (isInSection) { + if (startShowing >= i) { //because of fold skipping, we passed the close tag. In that case we cant do anything + if (!endOfDoc) { + return; + } else { + continue; + } + } + execute(SCI_SHOWLINES, startShowing, i-1); + if (!endOfDoc) { + return; //done, only single section requested + } //otherwise keep going + } + isInSection = false; + } + if ( ((state & (1 << MARK_HIDELINESBEGIN)) != 0) ) { + isInSection = true; + startShowing = i+1; + if (doDelete) + execute(SCI_MARKERDELETE, i, MARK_HIDELINESBEGIN); + } + + int levelLine = execute(SCI_GETFOLDLEVEL, i, 0); + if (levelLine & SC_FOLDLEVELHEADERFLAG) { //fold section. Dont show lines if fold is closed + if (isInSection && execute(SCI_GETFOLDEXPANDED, i) == 0) { + execute(SCI_SHOWLINES, startShowing, i); + startShowing = execute(SCI_GETLASTCHILD, i, (levelLine & SC_FOLDLEVELNUMBERMASK)); + } + } + } + } +} diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index 6df7d8e37..40ac09d4d 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -139,7 +139,7 @@ class ScintillaEditView : public Window public: ScintillaEditView() : Window(), _pScintillaFunc(NULL),_pScintillaPtr(NULL), - _currentIndex(0), _folderStyle(FOLDER_STYLE_BOX), _maxNbDigit(_MARGE_LINENUMBER_NB_CHIFFRE), _wrapRestoreNeeded(false) + _folderStyle(FOLDER_STYLE_BOX), _maxNbDigit(_MARGE_LINENUMBER_NB_CHIFFRE), _wrapRestoreNeeded(false) { ++_refCount; }; @@ -155,7 +155,6 @@ public: }; virtual void destroy() { - removeAllUnusedDocs(); ::DestroyWindow(_hSelf); _hSelf = NULL; }; @@ -166,103 +165,22 @@ public: return _pScintillaFunc(_pScintillaPtr, static_cast(Msg), static_cast(wParam), static_cast(lParam)); }; - void defineDocType(LangType typeDoc); + void activateBuffer(BufferID buffer); - bool setCurrentDocType(LangType typeDoc) { - if ((_buffers[_currentIndex]._lang == typeDoc) && (typeDoc != L_USER)) - return false; - if (typeDoc == L_USER) - _buffers[_currentIndex]._userLangExt[0] = '\0'; - - _buffers[_currentIndex]._lang = typeDoc; - defineDocType(typeDoc); - return true; - }; - - void setCurrentDocUserType(const char *userLangName) { + /*void setCurrentDocUserType(const char *userLangName) { strcpy(_buffers[_currentIndex]._userLangExt, userLangName); _buffers[_currentIndex]._lang = L_USER; defineDocType(L_USER); - }; + };*/ - char * attatchDefaultDoc(int nb); - - int findDocIndexByName(const char *fn) const; - char * activateDocAt(int index); - char * createNewDoc(const char *fn); - char * createNewDoc(int nbNew); - int getCurrentDocIndex() const {return _currentIndex;}; - const char * getCurrentTitle() const {return _buffers[_currentIndex]._fullPathName;}; - int setCurrentTitle(const char *fn) { - _buffers[_currentIndex].setFileName(fn); - defineDocType(_buffers[_currentIndex]._lang); - return _currentIndex; - }; - int closeCurrentDoc(int & i2Activate); - void closeDocAt(int i2Close); - - void removeAllUnusedDocs(); + BufferID attachDefaultDoc(); void getText(char *dest, int start, int end) const; - void setCurrentDocState(bool isDirty) { - _buffers[_currentIndex]._isDirty = isDirty; - }; - - bool isCurrentDocDirty() const { - return _buffers[_currentIndex]._isDirty; - }; - - void setCurrentDocReadOnly(bool isReadOnly) { - _buffers[_currentIndex]._isReadOnly = isReadOnly; - execute(SCI_SETREADONLY, isReadOnly); - }; - - bool setCurrentDocReadOnlyByUser(bool ro) { - execute(SCI_SETREADONLY, ro); - return _buffers[_currentIndex].setReadOnly(ro); - }; - - void updateCurrentDocSysReadOnlyStat() { - _buffers[_currentIndex].checkIfReadOnlyFile(); - }; - - bool isCurrentBufReadOnly() const { - return _buffers[_currentIndex].isReadOnly(); - }; - - bool isCurrentBufSysReadOnly() const { - return _buffers[_currentIndex].isSystemReadOnly(); - }; - - bool isCurrentBufUserReadOnly() const { - return _buffers[_currentIndex].isUserReadOnly(); - }; - - bool isAllDocsClean() const { - for (int i = 0 ; i < static_cast(_buffers.size()) ; i++) - if (_buffers[i]._isDirty) - return false; - return true; - }; - - size_t getNbDoc() const { - return _buffers.size(); - }; - void saveCurrentPos(); void restoreCurrentPos(); - - - Buffer & getBufferAt(size_t index) { - if (index >= _buffers.size()) - throw int(index); - return _buffers[index]; - }; - - void updateCurrentBufTimeStamp() { - _buffers[_currentIndex].updatTimeStamp(); - }; + void saveCurrentFold(); + void restoreCurrentFold(); int getCurrentDocLen() const { return int(execute(SCI_GETLENGTH)); @@ -284,10 +202,6 @@ public: getText(str, startPos, caretPos); }; - LangType getCurrentDocType() const { - return _buffers[_currentIndex]._lang; - }; - void doUserDefineDlg(bool willBeShown = true, bool isRTL = false) { _userDefineDlg.doDialog(willBeShown, isRTL); }; @@ -299,24 +213,11 @@ public: execute(SCI_SETCARETWIDTH, width); }; - // if we use this method, it must be via the - // gotoAnotherView or cloneToAnotherEditView - // So the ref counter of document should increase - int addBuffer(Buffer & buffer) { - _buffers.push_back(buffer); - execute(SCI_ADDREFDOCUMENT, 0, buffer._doc); - return (int(_buffers.size()) - 1); - }; - - Buffer & getCurrentBuffer() { - return getBufferAt(_currentIndex); - }; - void beSwitched() { _userDefineDlg.setScintilla(this); }; - //Marge memeber and method + //Marge member and method static const int _SC_MARGE_LINENUMBER; static const int _SC_MARGE_SYBOLE; static const int _SC_MARGE_FOLDER; @@ -391,16 +292,6 @@ public: execute(SCI_SETWRAPVISUALFLAGS, willBeShown?SC_WRAPVISUALFLAG_END:SC_WRAPVISUALFLAG_NONE); }; - void sortBuffer(int destIndex, int scrIndex) { - // Do nothing if there's no change of the position - if (scrIndex == destIndex) - return; - - Buffer buf2Insert = _buffers.at(scrIndex); - _buffers.erase(_buffers.begin() + scrIndex); - _buffers.insert(_buffers.begin() + destIndex, buf2Insert); - }; - int getSelectedTextCount() { CharacterRange range = getSelection(); return (range.cpMax - range.cpMin); @@ -454,7 +345,7 @@ public: long getTextHeight()const{ return long(execute(SCI_TEXTHEIGHT)); - }; + }; void gotoLine(int line){ if (line < execute(SCI_GETLINECOUNT)) @@ -487,8 +378,6 @@ public: execute(SCI_SETMARGINWIDTHN, 0, pixelWidth); }; - void setCurrentIndex(int index2Set) {_currentIndex = index2Set;}; - void setCurrentLineHiLiting(bool isHiliting, COLORREF bgColor) const { execute(SCI_SETCARETLINEVISIBLE, isHiliting); if (!isHiliting) @@ -503,26 +392,6 @@ public: void performGlobalStyles(); void expand(int &line, bool doExpand, bool force = false, int visLevels = 0, int level = -1); - void removeUserLang(const char *name) { - for (int i = 0 ; i < int(_buffers.size()) ; i++) - { - if ((_buffers[i]._lang == L_USER) && (!strcmp(name, _buffers[i]._userLangExt))) - { - _buffers[i]._userLangExt[0] = '\0'; - } - } - }; - void renameUserLang(const char *oldName, const char *newName) { - for (int i = 0 ; i < int(_buffers.size()) ; i++) - { - if ((_buffers[i]._lang == L_USER) && (!strcmp(oldName, _buffers[i]._userLangExt))) - { - strcpy(_buffers[i]._userLangExt, newName); - } - } - }; - - void currentLineUp() const { int currentLine = getCurrentLineNumber(); @@ -537,8 +406,6 @@ public: }; void currentLineDown() const { - - int currentLine = getCurrentLineNumber(); if (currentLine != (execute(SCI_GETLINECOUNT) - 1)) { @@ -571,7 +438,7 @@ public: void collapse(int level2Collapse, bool mode); void foldAll(bool mode); void foldCurrentPos(bool mode); - int getCodpage() const {return _codepage;}; + int getCodepage() const {return _codepage;}; //int getMaxNbDigit const () {return _maxNbDigit;}; @@ -584,26 +451,6 @@ public: return false; }; - int getNextPriorityIndex(int & weight, int heavest) { - weight = 0; - if (_buffers.size() <= 0) - return -1; - if (_buffers[0]._recentTag < heavest) - weight = _buffers[0]._recentTag; - - int maxIndex = 0; - - for (size_t i = 1 ; i < _buffers.size() ; i++) - { - if ((_buffers[i]._recentTag < heavest) && (weight < _buffers[i]._recentTag)) - { - weight = _buffers[i]._recentTag; - maxIndex = i; - } - } - return maxIndex; - }; - NppParameters * getParameter() { return _pParameter; }; @@ -614,7 +461,6 @@ public: void columnReplace(const ColumnModeInfo & cmi, const char ch); void columnReplace(ColumnModeInfo & cmi, int initial, int incr, unsigned char format); - void recalcHorizontalScrollbar(); void foldChanged(int line, int levelNow, int levelPrev); void clearIndicator(int indicatorNumber) { int docStart = 0; @@ -624,6 +470,17 @@ public: }; static LanguageName ScintillaEditView::langNames[L_EXTERNAL+1]; + + void bufferUpdated(Buffer * buffer, int mask); + BufferID getCurrentBufferID() { return _currentBufferID; }; + Buffer * getCurrentBuffer() { return _currentBuffer; }; + void styleChange(); + + void hideLines(); + + bool markerMarginClick(int lineNumber); //true if it did something + void notifyMarkers(Buffer * buf, bool isHide, int location, bool del); + void runMarkers(bool doHide, int searchStart, bool endOfDoc, bool doDelete); protected: static HINSTANCE _hLib; static int _refCount; @@ -657,16 +514,12 @@ protected: SCINTILLA_FUNC _pScintillaFunc; SCINTILLA_PTR _pScintillaPtr; - // the current active buffer index of _buffers - int _currentIndex; static WNDPROC _scintillaDefaultProc; CallWindowProcFunc _callWindowProc; - // the list of docs - buf_vec_t _buffers; - - // For the file nfo - //int _MSLineDrawFont; + //Store the current buffer so it can be retrieved later + BufferID _currentBufferID; + Buffer * _currentBuffer; folderStyle _folderStyle; @@ -680,6 +533,8 @@ protected: bool _wrapRestoreNeeded; //Lexers and Styling + void defineDocType(LangType typeDoc); //setup stylers for active document + void restyleBuffer(); const char * getCompleteKeywordList(std::string & kwl, LangType langType, int keywordIndex); void setKeywords(LangType langType, const char *keywords, int index); void setLexer(int lexerID, LangType langType, int whichList); @@ -887,7 +742,6 @@ protected: }; bool expandWordSelection(); - void arrangeBuffers(UINT nItems, UINT *items); }; #endif //SCINTILLA_EDIT_VIEW_H diff --git a/PowerEditor/src/ScitillaComponent/UserDefineDialog.cpp b/PowerEditor/src/ScitillaComponent/UserDefineDialog.cpp index 47521a56a..1d66005f4 100644 --- a/PowerEditor/src/ScitillaComponent/UserDefineDialog.cpp +++ b/PowerEditor/src/ScitillaComponent/UserDefineDialog.cpp @@ -83,8 +83,8 @@ bool SharedParametersDialog::setPropertyByCheck(HWND hwnd, WPARAM id, bool & boo { bool2set = (BST_CHECKED == ::SendMessage(::GetDlgItem(hwnd, id), BM_GETCHECK, 0, 0)); - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } @@ -171,8 +171,8 @@ BOOL CALLBACK SharedParametersDialog::run_dlgProc(UINT Message, WPARAM wParam, L { setKeywords2List(LOWORD(wParam)); - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } @@ -206,8 +206,8 @@ BOOL CALLBACK SharedParametersDialog::run_dlgProc(UINT Message, WPARAM wParam, L { style._fontName = (char *)::SendDlgItemMessage(_hSelf, LOWORD(wParam), CB_GETITEMDATA, i, 0); } - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } } @@ -250,8 +250,8 @@ BOOL CALLBACK SharedParametersDialog::run_dlgProc(UINT Message, WPARAM wParam, L //::MessageBox(NULL, "Bingo!!!", "", MB_OK); } } - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } return FALSE; @@ -819,8 +819,8 @@ void SymbolsStyleDialog::symbolAction(bool action) } _pUserLang->_keywordLists[3][--j] = '\0'; - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); } void SymbolsStyleDialog::listboxsRemoveAll() @@ -995,8 +995,8 @@ BOOL CALLBACK SymbolsStyleDialog::run_dlgProc(UINT Message, WPARAM wParam, LPARA if ((wParam == IDC_ADD_BUTTON) || (wParam == IDC_REMOVE_BUTTON)) { symbolAction((wParam == IDC_ADD_BUTTON)?ADD:REMOVE); - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } // car LBN_SELCHANGE == CBN_SELCHANGE == 1 @@ -1048,8 +1048,8 @@ BOOL CALLBACK SymbolsStyleDialog::run_dlgProc(UINT Message, WPARAM wParam, LPARA char *delims = _pUserLang->_keywordLists[KWL_DELIM_INDEX]; delims[symbIndex] = charStr[0]?charStr[0]:'0'; - if (_pScintilla->getCurrentDocType() == L_USER) - _pScintilla->defineDocType(L_USER); + if (_pScintilla->getCurrentBuffer()->getLangType() == L_USER) + _pScintilla->styleChange(); return TRUE; } else diff --git a/PowerEditor/src/Utf8_16.h b/PowerEditor/src/Utf8_16.h index ab1740f5f..e473f9e04 100644 --- a/PowerEditor/src/Utf8_16.h +++ b/PowerEditor/src/Utf8_16.h @@ -18,6 +18,7 @@ // - Removing UCS-Bug in Utf8_Iter // - Add convert function in Utf8_16_Write //////////////////////////////////////////////////////////////////////////////// +#pragma once #include #include diff --git a/PowerEditor/src/WinControls/TabBar/TabBar.cpp b/PowerEditor/src/WinControls/TabBar/TabBar.cpp index 5fbd7e4d4..90912691c 100644 --- a/PowerEditor/src/WinControls/TabBar/TabBar.cpp +++ b/PowerEditor/src/WinControls/TabBar/TabBar.cpp @@ -276,13 +276,14 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara } ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam); + int currentTabOn = ::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0); if (wParam == 2) return TRUE; if (_doDragNDrop) { - _nSrcTab = _nTabDragged = ::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0); + _nSrcTab = _nTabDragged = currentTabOn; POINT point; point.x = LOWORD(lParam); @@ -295,15 +296,21 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara } } - NMHDR nmhdr; - nmhdr.hwndFrom = _hSelf; - nmhdr.code = NM_CLICK; - nmhdr.idFrom = reinterpret_cast(this); + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = NM_CLICK; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = currentTabOn; ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); return TRUE; } + case WM_RBUTTONDOWN : //rightclick selects tab aswell + { + ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); + return TRUE; + } case WM_MOUSEMOVE : { @@ -353,6 +360,9 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara case WM_LBUTTONUP : { + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); + int currentTabOn = getTabIndexAt(xPos, yPos); if (_isDragging) { if(::GetCapture() == _hSelf) @@ -362,10 +372,11 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara // nmhdr.idFrom = this // destIndex = this->_nSrcTab // scrIndex = this->_nTabDragged - NMHDR nmhdr; - nmhdr.hwndFrom = _hSelf; - nmhdr.code = _isDraggingInside?TCN_TABDROPPED:TCN_TABDROPPEDOUTSIDE; - nmhdr.idFrom = reinterpret_cast(this); + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = _isDraggingInside?TCN_TABDROPPED:TCN_TABDROPPEDOUTSIDE; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = currentTabOn; ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); return TRUE; @@ -373,19 +384,14 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara if (_drawTabCloseButton) { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - - int currentTabOn = getTabIndexAt(xPos, yPos); - if ((_whichCloseClickDown == currentTabOn) && _closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect)) { - NMHDR nmhdr; - nmhdr.hwndFrom = _hSelf; - nmhdr.code = TCN_TABDELETE; - nmhdr.idFrom = reinterpret_cast(this); + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = TCN_TABDELETE; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = currentTabOn; - ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); _whichCloseClickDown = -1; @@ -422,12 +428,14 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara case WM_MBUTTONUP: { - ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); - - NMHDR nmhdr; - nmhdr.hwndFrom = _hSelf; - nmhdr.code = TCN_TABDELETE; - nmhdr.idFrom = reinterpret_cast(this); + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); + int currentTabOn = getTabIndexAt(xPos, yPos); + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = TCN_TABDELETE; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = currentTabOn; ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); return TRUE; @@ -435,13 +443,16 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara case WM_LBUTTONDBLCLK : { - ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); if (_isDbClk2Close) { - NMHDR nmhdr; - nmhdr.hwndFrom = _hSelf; - nmhdr.code = TCN_TABDELETE; - nmhdr.idFrom = reinterpret_cast(this); + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); + int currentTabOn = getTabIndexAt(xPos, yPos); + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = TCN_TABDELETE; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = currentTabOn; ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); } @@ -726,7 +737,7 @@ void TabBarPlus::exchangeItemData(POINT point) //2. shift their data, and insert the source TCITEM itemData_nDraggedTab, itemData_shift; - itemData_nDraggedTab.mask = itemData_shift.mask = TCIF_IMAGE | TCIF_TEXT; + itemData_nDraggedTab.mask = itemData_shift.mask = TCIF_IMAGE | TCIF_TEXT | TCIF_PARAM; char str1[256]; char str2[256]; diff --git a/PowerEditor/src/WinControls/TabBar/TabBar.h b/PowerEditor/src/WinControls/TabBar/TabBar.h index ad70f849c..cbea04ca2 100644 --- a/PowerEditor/src/WinControls/TabBar/TabBar.h +++ b/PowerEditor/src/WinControls/TabBar/TabBar.h @@ -43,6 +43,11 @@ const int nbCtrlMax = 10; #define TABBAR_ACTIVETEXT "Active tab text" #define TABBAR_INACTIVETEXT "Inactive tabs" +struct TBHDR { + NMHDR hdr; + int tabOrigin; +}; + class TabBar : public Window { public: @@ -74,7 +79,14 @@ public: int insertAtEnd(const char *subTabName); void activateAt(int index) const { - ::SendMessage(_hSelf, TCM_SETCURSEL, index, 0); + if (getCurrentTabIndex() != index) { + ::SendMessage(_hSelf, TCM_SETCURSEL, index, 0);} + TBHDR nmhdr; + nmhdr.hdr.hwndFrom = _hSelf; + nmhdr.hdr.code = TCN_SELCHANGE; + nmhdr.hdr.idFrom = reinterpret_cast(this); + nmhdr.tabOrigin = index; + }; void getCurrentTitle(char *title, int titleLen); diff --git a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp index 0acc68436..720e7c531 100644 --- a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp +++ b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp @@ -1,7 +1,7 @@ #include #include "WindowsDlg.h" #include "WindowsDlgRc.h" -#include "ScintillaEditView.h" +#include "DocTabView.h" #include #include #include @@ -90,11 +90,11 @@ struct NumericStringEquivalence struct BufferEquivalent { NumericStringEquivalence _strequiv; - ScintillaEditView *_pView; + DocTabView *_pTab; int _iColumn; bool _reverse; - BufferEquivalent(ScintillaEditView *pView, int iColumn, bool reverse) - : _pView(pView), _iColumn(iColumn), _reverse(reverse) + BufferEquivalent(DocTabView *pTab, int iColumn, bool reverse) + : _pTab(pTab), _iColumn(iColumn), _reverse(reverse) {} bool operator()(int i1, int i2) const @@ -106,32 +106,26 @@ struct BufferEquivalent bool compare(int i1, int i2) const { - const Buffer& b1 = _pView->getBufferAt(i1); - const Buffer& b2 = _pView->getBufferAt(i2); + BufferID bid1 = _pTab->getBufferByIndex(i1); + BufferID bid2 = _pTab->getBufferByIndex(i2); + Buffer * b1 = MainFileManager->getBufferByID(bid1); + Buffer * b2 = MainFileManager->getBufferByID(bid2); if (_iColumn == 0) { - const char *s1 = PathFindFileName(b1.getFileName()); - const char *s2 = PathFindFileName(b2.getFileName()); + const char *s1 = b1->getFileName(); + const char *s2 = b2->getFileName(); return _strequiv(s1, s2); } else if (_iColumn == 1) { - char buf1[MAX_PATH]; - char buf2[MAX_PATH]; - const char *f1 = b1.getFileName(); - const char *f2 = b2.getFileName(); - const char *s1 = PathFindFileName(b1.getFileName()); - const char *s2 = PathFindFileName(b2.getFileName()); - int l1 = min((s1 - f1), (_countof(buf1)-1)); - int l2 = min((s2 - f2), (_countof(buf2)-1)); - strncpy(buf1, f1, l1); buf1[l1] = 0; - strncpy(buf2, f2, l2); buf2[l2] = 0; - return _strequiv(buf1, buf2); + const char *s1 = b1->getFilePath(); + const char *s2 = b2->getFilePath(); + return _strequiv(s1, s2); //we can compare the full path to sort on directory, since after sorting directories sorting files is the second thing to do (if directories are the same that is) } else if (_iColumn == 2) { - int t1 = (int)b1.getLangType(); - int t2 = (int)b2.getLangType(); + int t1 = (int)b1->getLangType(); + int t2 = (int)b2->getLangType(); return (t1 < t2); // yeah should be the name } return false; @@ -173,17 +167,17 @@ WindowsDlg::WindowsDlg() : MyBaseClass(WindowsDlgMap), _isSorted(false) _szMinListCtrl = SIZEZERO; } -void WindowsDlg::init(HINSTANCE hInst, HWND parent, ScintillaEditView *pView) +void WindowsDlg::init(HINSTANCE hInst, HWND parent, DocTabView *pTab) { MyBaseClass::init(hInst, parent); - _pView = pView; + _pTab = pTab; } void WindowsDlg::init(HINSTANCE hInst, HWND parent) { assert(!"Call other initialize method"); MyBaseClass::init(hInst, parent); - _pView = NULL; + _pTab = NULL; } BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) @@ -244,20 +238,22 @@ BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam if(pLvdi->item.mask & LVIF_TEXT) { pLvdi->item.pszText[0] = 0; - size_t index = pLvdi->item.iItem; - if (index >= _pView->getNbDoc() || index >= _idxMap.size()) + int index = pLvdi->item.iItem; + if (index >= _pTab->nbItem() || index >= (int)_idxMap.size()) return FALSE; index = _idxMap[index]; - const Buffer& buffer = _pView->getBufferAt(index); + //const Buffer& buffer = _pView->getBufferAt(index); + BufferID bufID = _pTab->getBufferByIndex(index); + Buffer * buf = MainFileManager->getBufferByID(bufID); if (pLvdi->item.iSubItem == 0) // file name { int len = pLvdi->item.cchTextMax; - const char *fullName = buffer.getFileName(); - strncpy(pLvdi->item.pszText, PathFindFileName(fullName), len-1); + const char *fileName = buf->getFileName(); + strncpy(pLvdi->item.pszText, fileName, len-1); pLvdi->item.pszText[len-1] = 0; len = strlen(pLvdi->item.pszText); - if (buffer.isDirty()) + if (buf->isDirty()) { if (len < pLvdi->item.cchTextMax) { @@ -265,7 +261,7 @@ BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam pLvdi->item.pszText[len] = 0; } } - else if (buffer.isReadOnly()) + else if (buf->isReadOnly()) { len += strlen(readonlyString); if (len <= pLvdi->item.cchTextMax) @@ -274,9 +270,13 @@ BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam } else if (pLvdi->item.iSubItem == 1) // directory { - const char *fullName = buffer.getFileName(); - const char *fileName = PathFindFileName(fullName); - int len = fileName-fullName+1; + const char *fullName = buf->getFilePath(); + const char *fileName = buf->getFileName(); + int len = strlen(fullName)-strlen(fileName); + if (!len) { + len = 1; + fullName = ""; + } if (pLvdi->item.cchTextMax < len) len = pLvdi->item.cchTextMax; strncpy(pLvdi->item.pszText, fullName, len-1); @@ -286,7 +286,7 @@ BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam { int len = pLvdi->item.cchTextMax; NppParameters *pNppParameters = NppParameters::getInstance(); - Lang *lang = pNppParameters->getLangFromID(buffer.getLangType()); + Lang *lang = pNppParameters->getLangFromID(buf->getLangType()); if (NULL != lang) { strncpy(pLvdi->item.pszText, lang->getLangName(), len-1); @@ -316,7 +316,7 @@ BOOL CALLBACK WindowsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam vector sortMap; sortMap.resize(n); for (i=0; igetNbDoc() : 0; + size_t count = (_pTab != NULL) ? _pTab->nbItem() : 0; size_t oldSize = _idxMap.size(); if (!invalidate && count == oldSize) return; @@ -551,7 +551,7 @@ void WindowsDlg::fitColumnsToSize() void WindowsDlg::resetSelection() { - int curSel = _pView->getCurrentDocIndex(); + int curSel = _pTab->getCurrentTabIndex(); int pos = 0; for (vector::iterator itr = _idxMap.begin(), end = _idxMap.end(); itr != end; ++itr, ++pos) { @@ -654,7 +654,7 @@ void WindowsDlg::doClose() } delete[] nmdlg.Items; - if (_pView->getNbDoc() != _idxMap.size()) + if (_pTab->nbItem() != _idxMap.size()) doRefresh(true); else { @@ -738,25 +738,26 @@ void WindowsMenu::init(HINSTANCE hInst, HMENU hMainMenu, const char *translation InsertMenuItem(hMainMenu, pos, TRUE, &mii); } -void WindowsMenu::initPopupMenu(HMENU hMenu, ScintillaEditView *pView) +void WindowsMenu::initPopupMenu(HMENU hMenu, DocTabView *pTab) { if (hMenu == _hMenu) { - int curDoc = pView->getCurrentDocIndex(); + int curDoc = pTab->getCurrentTabIndex(); int nMaxDoc = IDM_WINDOW_MRU_LIMIT - IDM_WINDOW_MRU_FIRST + 1; - int nDoc = pView->getNbDoc(); + int nDoc = pTab->nbItem(); nDoc = min(nDoc, nMaxDoc); int id, pos; for (id=IDM_WINDOW_MRU_FIRST, pos=0; idgetBufferAt(pos); + BufferID bufID = pTab->getBufferByIndex(pos); + Buffer * buf = MainFileManager->getBufferByID(bufID); MENUITEMINFO mii; memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING|MIIM_STATE|MIIM_ID; - mii.dwTypeData = buildFileName(buffer, 60, pos, scbuf.getFileName()); + mii.dwTypeData = buildFileName(buffer, 60, pos, buf->getFileName()); mii.fState &= ~(MF_GRAYED|MF_DISABLED|MF_CHECKED); if (pos == curDoc) mii.fState |= MF_CHECKED; diff --git a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.h b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.h index 6635fd5f2..9b70b37fb 100644 --- a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.h +++ b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.h @@ -24,7 +24,7 @@ #include #include -class ScintillaEditView; +class DocTabView; typedef enum { WDT_ACTIVATE = 1, @@ -62,7 +62,7 @@ class WindowsDlg : public SizeableDlg public : WindowsDlg(); int doDialog(TiXmlNode *dlgNode); - virtual void init(HINSTANCE hInst, HWND parent, ScintillaEditView *pView); + virtual void init(HINSTANCE hInst, HWND parent, DocTabView *pTab); void doRefresh(bool invalidate = false); bool changeDlgLang(); @@ -86,7 +86,7 @@ protected : static RECT _lastKnownLocation; SIZE _szMinButton; SIZE _szMinListCtrl; - ScintillaEditView *_pView; + DocTabView *_pTab; std::vector _idxMap; int _lastSort; bool _isSorted; @@ -103,7 +103,7 @@ public: ~WindowsMenu(); void init(HINSTANCE hInst, HMENU hMainMenu, const char *translation); //void initMenu(HMENU hMenu, ScintillaEditView *pView); - void initPopupMenu(HMENU hMenu, ScintillaEditView *pView); + void initPopupMenu(HMENU hMenu, DocTabView *pTab); //void uninitPopupMenu(HMENU hMenu, ScintillaEditView *pView); private: char *buildFileName(char *buffer, int len, int pos, const char *filename); diff --git a/PowerEditor/src/lastRecentFileList.cpp b/PowerEditor/src/lastRecentFileList.cpp new file mode 100644 index 000000000..783903282 --- /dev/null +++ b/PowerEditor/src/lastRecentFileList.cpp @@ -0,0 +1,199 @@ +//this file is part of notepad++ +//Copyright (C)2003 Don HO +// +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU General Public License +//as published by the Free Software Foundation; either +//version 2 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include "lastRecentFileList.h" +#include "menuCmdID.h" + + +void LastRecentFileList::initMenu(HMENU hMenu, int idBase, int posBase) { + _hMenu = hMenu; + _idBase = idBase; + _posBase = posBase; + + for (int i = 0 ; i < sizeof(_idFreeArray) ; i++) + _idFreeArray[i] = true; +}; + +void LastRecentFileList::updateMenu() { + if (!_hasSeparators && _size > 0) { //add separators + const char * nativeLangOpenAllFiles = (NppParameters::getInstance())->getNativeLangMenuString(IDM_OPEN_ALL_RECENT_FILE); + const char * nativeLangCleanFilesList = (NppParameters::getInstance())->getNativeLangMenuString(IDM_CLEAN_RECENT_FILE_LIST); + + const char * openAllFileStr = nativeLangOpenAllFiles?nativeLangOpenAllFiles:"Open All Recent Files"; + const char * cleanFileListStr = nativeLangCleanFilesList?nativeLangCleanFilesList:"Clean Recent Files List"; + ::InsertMenu(_hMenu, _posBase + 0, MF_BYPOSITION, UINT(-1), 0); + ::InsertMenu(_hMenu, _posBase + 1, MF_BYPOSITION, IDM_OPEN_ALL_RECENT_FILE, openAllFileStr); + ::InsertMenu(_hMenu, _posBase + 2, MF_BYPOSITION, IDM_CLEAN_RECENT_FILE_LIST, cleanFileListStr); + ::InsertMenu(_hMenu, _posBase + 3, MF_BYPOSITION, UINT(-1), 0); + _hasSeparators = true; + + } else if (_hasSeparators && _size == 0) { //remove separators + ::RemoveMenu(_hMenu, _posBase + 3, MF_BYPOSITION); + ::RemoveMenu(_hMenu, IDM_CLEAN_RECENT_FILE_LIST, MF_BYCOMMAND); + ::RemoveMenu(_hMenu, IDM_OPEN_ALL_RECENT_FILE, MF_BYCOMMAND); + ::RemoveMenu(_hMenu, _posBase + 0, MF_BYPOSITION); + _hasSeparators = false; + + } + + //Remove all menu items + for(int i = 0; i < _size; i++) { + ::RemoveMenu(_hMenu, _lrfl.at(i)._id, MF_BYCOMMAND); + } + //Then readd them, so everything stays in sync + char indexBuffer[4]; + for(int j = 0; j < _size; j++) { + std::string menuString = ""; + if (j < 9) { //first 9 have accelerator (0 unused) + menuString += "&"; + } + itoa(j+1, indexBuffer, 10);//one based numbering + menuString += indexBuffer; + menuString += " "; + menuString += _lrfl.at(j)._name; + ::InsertMenu(_hMenu, _posBase + j, MF_BYPOSITION, _lrfl.at(j)._id, menuString.c_str()); + i++; + } +} + +void LastRecentFileList::add(const char *fn) { + if (_userMax == 0 || _locked) + return; + + RecentItem itemToAdd(fn); + + int index = find(fn); + if (index != -1) { //already in list, bump upwards + remove(index); + } + + if (_size == _userMax) { + itemToAdd._id = _lrfl.back()._id; + _lrfl.pop_back(); //remove oldest + } else { + itemToAdd._id = popFirstAvailableID(); + _size++; + } + _lrfl.push_front(itemToAdd); + updateMenu(); +}; + +void LastRecentFileList::remove(const char *fn) { + int index = find(fn); + if (index != -1) + remove(index); +}; + +void LastRecentFileList::remove(int index) { + if (_size == 0 || _locked) + return; + if (index > -1 && index < (int)_lrfl.size()) { + ::RemoveMenu(_hMenu, _lrfl.at(index)._id, MF_BYCOMMAND); + setAvailable(_lrfl.at(index)._id); + _lrfl.erase(_lrfl.begin() + index); + _size--; + updateMenu(); + } +}; + + +void LastRecentFileList::clear() { + if (_size == 0) + return; + + for(int i = (_size-1); i >= 0; i--) { + ::RemoveMenu(_hMenu, _lrfl.at(i)._id, MF_BYCOMMAND); + setAvailable(_lrfl.at(i)._id); + _lrfl.erase(_lrfl.begin() + i); + } + _size = 0; + updateMenu(); +} + + +std::string & LastRecentFileList::getItem(int id) { + int i = 0; + for(; i < _size; i++) { + if (_lrfl.at(i)._id == id) + break; + } + if (i == _size) + i = 0; + return _lrfl.at(i)._name; //if not found, return first +}; + +std::string & LastRecentFileList::getIndex(int index) { + return _lrfl.at(index)._name; //if not found, return first +}; + + +void LastRecentFileList::setUserMaxNbLRF(int size) { + if (size < _userMax) { //start popping items + int toPop = _userMax-size; + while(toPop > 0) { + ::RemoveMenu(_hMenu, _lrfl.back()._id, MF_BYCOMMAND); + setAvailable(_lrfl.back()._id); + _lrfl.pop_back(); + toPop--; + } + _size = size; + updateMenu(); + } + _userMax = size; +}; + + + +void LastRecentFileList::saveLRFL() { + NppParameters *pNppParams = NppParameters::getInstance(); + if (pNppParams->writeNbHistoryFile(_userMax)) + { + for(int i = _size - 1; i >= 0; i--) //reverse order: so loading goes in correct order + { + pNppParams->writeHistory(_lrfl.at(i)._name.c_str()); + } + } +}; + + + +int LastRecentFileList::find(const char *fn) { + int i = 0; + for(int i = 0; i < _size; i++) { + if (_lrfl.at(i)._name == fn) { + return i; + } + } + return -1; +}; + +int LastRecentFileList::popFirstAvailableID() { + for (int i = 0 ; i < NB_MAX_LRF_FILE ; i++) + { + if (_idFreeArray[i]) + { + _idFreeArray[i] = false; + return i + _idBase; + } + } + return 0; +}; + +void LastRecentFileList::setAvailable(int id) { + int index = id - _idBase; + _idFreeArray[index] = true; +}; diff --git a/PowerEditor/src/lastRecentFileList.h b/PowerEditor/src/lastRecentFileList.h index e0cae9229..9228e7d1c 100644 --- a/PowerEditor/src/lastRecentFileList.h +++ b/PowerEditor/src/lastRecentFileList.h @@ -1,128 +1,61 @@ #ifndef LASTRECENTFILELIST_H #define LASTRECENTFILELIST_H -#include +#include #include +#include "windows.h" +#include "Parameters.h" -typedef std::list stringList; +struct RecentItem { + int _id; + std::string _name; + RecentItem(const char * name) : _name(name) {}; +}; + +typedef std::deque recentList; class LastRecentFileList { public : - LastRecentFileList() : _hasSeparators(false){ + LastRecentFileList() : _hasSeparators(false), _size(0), _locked(false) { _userMax = (NppParameters::getInstance())->getNbMaxFile(); }; - void initMenu(HMENU hMenu, int idBase, int posBase) { - _hMenu = hMenu; - _idBase = idBase; - _posBase = posBase; + void initMenu(HMENU hMenu, int idBase, int posBase); - for (int i = 0 ; i < sizeof(_idFreeArray) ; i++) - _idFreeArray[i] = true; + void updateMenu(); + + void add(const char *fn); + void remove(const char *fn); + void remove(int index); + void clear(); + + int getSize() { + return _size; }; - - void add(const char *fn) { - if (_userMax == 0) - return; - - int size = _lrfl.size(); - - if (size >= _userMax) - { - _lrfl.erase(_lrfl.begin()); - - int id = ::GetMenuItemID(_hMenu, 0 + _posBase); - ::RemoveMenu(_hMenu, id, MF_BYCOMMAND); - setAvailable(id); - size--; - } - _lrfl.push_back(fn); - ::InsertMenu(_hMenu, _posBase + size, MF_BYPOSITION, popFirstAvailableID() + _idBase, fn); - - if (!_hasSeparators) - { - const char * nativeLangOpenAllFiles = (NppParameters::getInstance())->getNativeLangMenuString(IDM_OPEN_ALL_RECENT_FILE); - const char * nativeLangCleanFilesList = (NppParameters::getInstance())->getNativeLangMenuString(IDM_CLEAN_RECENT_FILE_LIST); - - const char * openAllFileStr = nativeLangOpenAllFiles?nativeLangOpenAllFiles:"Open All Recent Files"; - const char * cleanFileListStr = nativeLangCleanFilesList?nativeLangCleanFilesList:"Clean Recent Files List"; - ::InsertMenu(_hMenu, _posBase + size + 1, MF_BYPOSITION, UINT(-1), 0); - ::InsertMenu(_hMenu, _posBase + size + 2, MF_BYPOSITION, IDM_OPEN_ALL_RECENT_FILE, openAllFileStr); - ::InsertMenu(_hMenu, _posBase + size + 3, MF_BYPOSITION, IDM_CLEAN_RECENT_FILE_LIST, cleanFileListStr); - ::InsertMenu(_hMenu, _posBase + size + 4, MF_BYPOSITION, UINT(-1), 0); - _hasSeparators = true; - } - }; - - void remove(const char *fn) { - if (find2Remove(fn)) - { - int id = 0; - char filename[MAX_PATH]; - for (size_t i = 0 ; i < _lrfl.size() + 1 ; i++) - { - ::GetMenuString(_hMenu, i + _posBase, filename, sizeof(filename), MF_BYPOSITION); - - if (!strcmp(fn, filename)) - { - id = ::GetMenuItemID(_hMenu, i + _posBase); - break; - } - } - ::RemoveMenu(_hMenu, id, MF_BYCOMMAND); - setAvailable(id); - - int size; - if (!(size = _lrfl.size())) - { - ::RemoveMenu(_hMenu, _posBase + 3, MF_BYPOSITION); - ::RemoveMenu(_hMenu, _posBase + 0, MF_BYPOSITION); - ::RemoveMenu(_hMenu, IDM_OPEN_ALL_RECENT_FILE, MF_BYCOMMAND); - ::RemoveMenu(_hMenu, IDM_CLEAN_RECENT_FILE_LIST, MF_BYCOMMAND); - _hasSeparators = false; - } - } - }; - /* - int getNbLRF() const { - return _lrfl.size(); - }; -*/ int getMaxNbLRF() const { return NB_MAX_LRF_FILE; }; - void setUserMaxNbLRF(int size) { - _userMax = size; - }; - int getUserMaxNbLRF() const { return _userMax; }; + + std::string & getItem(int id); //use menu id + std::string & getIndex(int index); //use menu id - void saveLRFL() const { - NppParameters *pNppParams = NppParameters::getInstance(); - if (pNppParams->writeNbHistoryFile(_userMax)) - { - // if user defined nb recent files smaller than the size of list, - // we just keep the newest ones - int decal = _lrfl.size() - _userMax; - decal = (decal >= 0)?decal:0; - stringList::const_iterator it = _lrfl.begin(); - for (int i = 0 ; i < decal ; i++, it++); + void setUserMaxNbLRF(int size); - for (int i = 0 ; it != _lrfl.end() && (i < _userMax) ; it++, i++) - { - pNppParams->writeHistory(((const std::string)*it).c_str()); - } - } + void saveLRFL(); + + void setLock(bool lock) { + _locked = lock; }; - private: - stringList _lrfl; + recentList _lrfl; int _userMax; + int _size; // For the menu HMENU _hMenu; @@ -130,42 +63,12 @@ private: int _idBase; bool _idFreeArray[NB_MAX_LRF_FILE]; bool _hasSeparators; + bool _locked; - bool find(const char *fn) const { - for (stringList::const_iterator it = _lrfl.begin() ; it != _lrfl.end() ; it++) - if (*it == fn) - return true; - return false; - }; + int find(const char *fn); - bool find2Remove(const char *fn) { - for (stringList::iterator it = _lrfl.begin() ; it != _lrfl.end() ; it++) - { - if (*it == fn) - { - _lrfl.erase(it); - return true; - } - } - return false; - }; - - int popFirstAvailableID() { - for (int i = 0 ; i < NB_MAX_LRF_FILE ; i++) - { - if (_idFreeArray[i]) - { - _idFreeArray[i] = false; - return i; - } - } - return 0; - }; - - void setAvailable(int id) { - int index = id - _idBase; - _idFreeArray[index] = true; - }; + int popFirstAvailableID(); + void setAvailable(int id); }; #endif //LASTRECENTFILELIST_H diff --git a/PowerEditor/src/menuCmdID.h b/PowerEditor/src/menuCmdID.h index cb0f2ab25..ef952831c 100644 --- a/PowerEditor/src/menuCmdID.h +++ b/PowerEditor/src/menuCmdID.h @@ -178,6 +178,9 @@ #define IDM_VIEW_GOTO_ANOTHER_VIEW 10001 #define IDM_VIEW_CLONE_TO_ANOTHER_VIEW 10002 + + #define IDM_VIEW_SWITCHTO_MAIN (IDM_VIEW + 70) + #define IDM_VIEW_SWITCHTO_SUB (IDM_VIEW + 71) #define IDM_FORMAT (IDM + 5000) diff --git a/PowerEditor/src/resource.h b/PowerEditor/src/resource.h index 09756dc7f..016f4f55b 100644 --- a/PowerEditor/src/resource.h +++ b/PowerEditor/src/resource.h @@ -279,8 +279,8 @@ #define NPPM_INTERNAL_SCINTILLAKEYMODIFIED (NOTEPADPLUS_USER_INTERNAL + 7) #define NPPM_INTERNAL_SCINTILLAFINFERCOLLAPSE (NOTEPADPLUS_USER_INTERNAL + 8) #define NPPM_INTERNAL_SCINTILLAFINFERUNCOLLAPSE (NOTEPADPLUS_USER_INTERNAL + 9) - #define NPPM_INTERNAL_DOCSWITCHOFF (NOTEPADPLUS_USER_INTERNAL + 10) - #define NPPM_INTERNAL_DOCSWITCHIN (NOTEPADPLUS_USER_INTERNAL + 11) + //#define NPPM_INTERNAL_DOCSWITCHOFF (NOTEPADPLUS_USER_INTERNAL + 10) + //#define NPPM_INTERNAL_DOCSWITCHIN (NOTEPADPLUS_USER_INTERNAL + 11) #define NPPM_INTERNAL_ISTABBARREDUCED (NOTEPADPLUS_USER_INTERNAL + 12) #define NPPM_INTERNAL_ISFOCUSEDTAB (NOTEPADPLUS_USER_INTERNAL + 13) #define NPPM_INTERNAL_GETMENU (NOTEPADPLUS_USER_INTERNAL + 14) diff --git a/PowerEditor/src/winmain.cpp b/PowerEditor/src/winmain.cpp index d203bc1ea..8fd68d388 100644 --- a/PowerEditor/src/winmain.cpp +++ b/PowerEditor/src/winmain.cpp @@ -138,6 +138,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, int nCmdSh size_t nrFilesToOpen = params.size(); const char * currentFile; char fullFileName[MAX_PATH]; + //TODO: try merging the flenames and see if it exists, user may have typed a single spaced filename without quotes for(size_t i = 0; i < nrFilesToOpen; i++) { currentFile = params.at(i); //check if relative or full path. Relative paths dont have a colon for driveletter @@ -160,6 +161,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, int nCmdSh // First of all, destroy static object NppParameters pNppParameters->destroyInstance(); + MainFileManager->destroyInstance(); + int sw; @@ -261,24 +264,25 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, int nCmdSh ::MessageBox(NULL, strcat(str, code), "Notepad++ Exception", MB_OK); } doException(notepad_plus_plus); - } catch(std::exception ex) { - ::MessageBox(NULL, ex.what(), "C++ Exception", MB_OK); - doException(notepad_plus_plus); } catch (const Win32Exception & ex) { char message[1024]; //TODO: sane number sprintf(message, "An exception occured. Notepad++ cannot recover and must be shut down.\r\nThe exception details are as follows:\r\n" - "Code:\t0x%08X\r\nType:\t%s\r\nException address: 0x%08X" - "\r\n\r\nNotepad++ will attempt to save any unsaved data. However, dataloss is very likely.", + "Code:\t0x%08X\r\nType:\t%s\r\nException address: 0x%08X", ex.code(), ex.what(), ex.where()); ::MessageBox(NULL, message, "Win32Exception", MB_OK | MB_ICONERROR); doException(notepad_plus_plus); + } catch(std::exception ex) { + ::MessageBox(NULL, ex.what(), "C++ Exception", MB_OK); + doException(notepad_plus_plus); } catch(...) { //this shouldnt ever have to happen doException(notepad_plus_plus); } + return (UINT)msg.wParam; } void doException(Notepad_plus & notepad_plus_plus) { + _set_se_translator(NULL); //disable exception handler after excpetion, we dont want corrupt data structurs to crash the exception handler ::MessageBox(NULL, "Notepad++ will attempt to save any unsaved data. However, dataloss is very likely.", "Recovery initiating", MB_OK | MB_ICONINFORMATION); bool res = notepad_plus_plus.emergency(); if (res) { diff --git a/PowerEditor/visual.net/notepadPlus.vc.7.0.vcproj b/PowerEditor/visual.net/notepadPlus.vc.7.0.vcproj index 30fd6f2e7..19eec3e48 100644 --- a/PowerEditor/visual.net/notepadPlus.vc.7.0.vcproj +++ b/PowerEditor/visual.net/notepadPlus.vc.7.0.vcproj @@ -89,15 +89,17 @@ IF NOT EXIST ..\bin\userDefineLang.xml COPY ..\src\userDefineLang.xml ..\bin\use WholeProgramOptimization="TRUE"> + +