diff --git a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp index 6104f929e..fdccdcb2c 100644 --- a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp +++ b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp @@ -317,7 +317,7 @@ int PluginsManager::loadPluginFromPath(const TCHAR *pluginFilePath) } } -bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginUpdateInfoList) +bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginUpdateInfoList, PluginViewList* pluginImcompatibleList) { if (_isDisabled) return false; @@ -350,6 +350,9 @@ bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginU Version nppVer; nppVer.setVersionFrom(nppFullPathName); + const TCHAR* incompatibleWarning = L"%s's version %s is not compatible to this version of Notepad++ (v%s).\r\nAs a result the plugin cannot be loaded."; + const TCHAR* incompatibleWarningWithSolution = L"%s's version %s is not compatible to this version of Notepad++ (v%s).\r\nAs a result the plugin cannot be loaded.\r\n\r\nGo to Updates section and update your plugin to %s for solving the compatibility issue."; + // get plugin folder if (hFindFolder != INVALID_HANDLE_VALUE && (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { @@ -385,6 +388,16 @@ bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginU { // Find compatible Notepad++ versions isCompatible = nppVer.isCompatibleTo(pui->_nppCompatibleVersions.first, pui->_nppCompatibleVersions.second); + + if (!isCompatible && pluginImcompatibleList) + { + PluginUpdateInfo* incompatiblePlg = new PluginUpdateInfo(*pui); + incompatiblePlg->_version = v; + TCHAR msg[1024]; + wsprintf(msg, incompatibleWarning, incompatiblePlg->_displayName.c_str(), v.toString().c_str(), nppVer.toString().c_str()); + incompatiblePlg->_description = msg; + pluginImcompatibleList->pushBack(incompatiblePlg); + } } else if (v < pui->_version && // If dll version is older, and _oldVersionCompatibility is valid (not empty), we search in "_oldVersionCompatibility" !(pui->_oldVersionCompatibility.first.first.empty() && pui->_oldVersionCompatibility.first.second.empty()) && // first version interval is valid @@ -393,6 +406,16 @@ bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginU if (v.isCompatibleTo(pui->_oldVersionCompatibility.first.first, pui->_oldVersionCompatibility.first.second)) // dll older version found { isCompatible = nppVer.isCompatibleTo(pui->_oldVersionCompatibility.second.first, pui->_oldVersionCompatibility.second.second); + + if (!isCompatible && pluginImcompatibleList) + { + PluginUpdateInfo* incompatiblePlg = new PluginUpdateInfo(*pui); + incompatiblePlg->_version = v; + TCHAR msg[1024]; + wsprintf(msg, incompatibleWarningWithSolution, incompatiblePlg->_displayName.c_str(), v.toString().c_str(), nppVer.toString().c_str(), pui->_version.toString().c_str()); + incompatiblePlg->_description = msg; + pluginImcompatibleList->pushBack(incompatiblePlg); + } } } } @@ -443,6 +466,16 @@ bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginU { // Find compatible Notepad++ versions isCompatible2 = nppVer.isCompatibleTo(pui2->_nppCompatibleVersions.first, pui2->_nppCompatibleVersions.second); + + if (!isCompatible2 && pluginImcompatibleList) + { + PluginUpdateInfo* incompatiblePlg = new PluginUpdateInfo(*pui2); + incompatiblePlg->_version = v2; + TCHAR msg[1024]; + wsprintf(msg, incompatibleWarning, incompatiblePlg->_displayName.c_str(), v2.toString().c_str(), nppVer.toString().c_str()); + incompatiblePlg->_description = msg; + pluginImcompatibleList->pushBack(incompatiblePlg); + } } else if (v2 < pui2->_version && // If dll version is older, and _oldVersionCompatibility is valid (not empty), we search in "_oldVersionCompatibility" !(pui2->_oldVersionCompatibility.first.first.empty() && pui2->_oldVersionCompatibility.first.second.empty()) && // first version interval is valid @@ -451,6 +484,16 @@ bool PluginsManager::loadPlugins(const TCHAR* dir, const PluginViewList* pluginU if (v2.isCompatibleTo(pui2->_oldVersionCompatibility.first.first, pui2->_oldVersionCompatibility.first.second)) // dll older version found { isCompatible2 = nppVer.isCompatibleTo(pui2->_oldVersionCompatibility.second.first, pui2->_oldVersionCompatibility.second.second); + + if (!isCompatible2 && pluginImcompatibleList) + { + PluginUpdateInfo* incompatiblePlg = new PluginUpdateInfo(*pui2); + incompatiblePlg->_version = v2; + TCHAR msg[1024]; + wsprintf(msg, incompatibleWarningWithSolution, incompatiblePlg->_displayName.c_str(), v2.toString().c_str(), nppVer.toString().c_str(), pui2->_version.toString().c_str()); + incompatiblePlg->_description = msg; + pluginImcompatibleList->pushBack(incompatiblePlg); + } } } } diff --git a/PowerEditor/src/MISC/PluginsManager/PluginsManager.h b/PowerEditor/src/MISC/PluginsManager/PluginsManager.h index 9b00db640..d39798df6 100644 --- a/PowerEditor/src/MISC/PluginsManager/PluginsManager.h +++ b/PowerEditor/src/MISC/PluginsManager/PluginsManager.h @@ -91,7 +91,7 @@ public: _nppData = nppData; } - bool loadPlugins(const TCHAR *dir = NULL, const PluginViewList* pluginUpdateInfoList = nullptr); + bool loadPlugins(const TCHAR *dir = NULL, const PluginViewList* pluginUpdateInfoList = nullptr, PluginViewList* pluginImcompatibleList = nullptr); bool unloadPlugin(int index, HWND nppHandle); @@ -133,16 +133,14 @@ private: int loadPluginFromPath(const TCHAR* pluginFilePath); - void pluginCrashAlert(const TCHAR *pluginName, const TCHAR *funcSignature) - { + void pluginCrashAlert(const TCHAR *pluginName, const TCHAR *funcSignature) { generic_string msg = pluginName; msg += TEXT(" just crashed in\r"); msg += funcSignature; ::MessageBox(NULL, msg.c_str(), TEXT("Plugin Crash"), MB_OK|MB_ICONSTOP); } - void pluginExceptionAlert(const TCHAR *pluginName, const std::exception& e) - { + void pluginExceptionAlert(const TCHAR *pluginName, const std::exception& e) { generic_string msg = TEXT("An exception occurred due to plugin: "); msg += pluginName; msg += TEXT("\r\n\r\nException reason: "); @@ -151,8 +149,7 @@ private: ::MessageBox(NULL, msg.c_str(), TEXT("Plugin Exception"), MB_OK); } - bool isInLoadedDlls(const TCHAR *fn) const - { + bool isInLoadedDlls(const TCHAR *fn) const { for (size_t i = 0; i < _loadedDlls.size(); ++i) if (generic_stricmp(fn, _loadedDlls[i]._fileName.c_str()) == 0) return true; diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index cce817bc4..81e68ce4b 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -425,7 +425,7 @@ LRESULT Notepad_plus::init(HWND hwnd) _pluginsManager.init(nppData); bool enablePluginAdmin = _pluginsAdminDlg.initFromJson(); - _pluginsManager.loadPlugins(nppParam.getPluginRootDir(), enablePluginAdmin ? &_pluginsAdminDlg.getAvailablePluginUpdateInfoList() : nullptr); + _pluginsManager.loadPlugins(nppParam.getPluginRootDir(), enablePluginAdmin ? &_pluginsAdminDlg.getAvailablePluginUpdateInfoList() : nullptr, enablePluginAdmin ? &_pluginsAdminDlg.getIncompatibleList() : nullptr); _restoreButton.init(_pPublicInterface->getHinst(), hwnd); // ------------ // diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp index f57e7db59..d7e9afca2 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp @@ -139,10 +139,12 @@ void PluginsAdminDlg::create(int dialogID, bool isRTL, bool msgDestParent) const TCHAR *available = TEXT("Available"); const TCHAR *updates = TEXT("Updates"); const TCHAR *installed = TEXT("Installed"); + const TCHAR *incompatible = TEXT("Incompatible"); _tab.insertAtEnd(available); _tab.insertAtEnd(updates); _tab.insertAtEnd(installed); + _tab.insertAtEnd(incompatible); rect.bottom -= dpiManager.scaleX(100); _tab.reSizeTo(rect); @@ -216,50 +218,46 @@ void PluginsAdminDlg::create(int dialogID, bool isRTL, bool msgDestParent) NativeLangSpeaker *pNativeSpeaker = nppParam.getNativeLangSpeaker(); generic_string pluginStr = pNativeSpeaker->getAttrNameStr(TEXT("Plugin"), "PluginAdmin", "Plugin"); generic_string vesionStr = pNativeSpeaker->getAttrNameStr(TEXT("Version"), "PluginAdmin", "Version"); - //generic_string stabilityStr = pNativeSpeaker->getAttrNameStr(TEXT("Stability"), "PluginAdmin", "Stability"); - - _availableList.addColumn(columnInfo(pluginStr, nppParam._dpiManager.scaleX(200))); - _availableList.addColumn(columnInfo(vesionStr, nppParam._dpiManager.scaleX(100))); - //_availableList.addColumn(columnInfo(stabilityStr, nppParam._dpiManager.scaleX(70))); - _availableList.setViewStyleOption(LVS_EX_CHECKBOXES); COLORREF fgColor = (NppParameters::getInstance()).getCurrentDefaultFgColor(); COLORREF bgColor = (NppParameters::getInstance()).getCurrentDefaultBgColor(); + _availableList.addColumn(columnInfo(pluginStr, nppParam._dpiManager.scaleX(200))); + _availableList.addColumn(columnInfo(vesionStr, nppParam._dpiManager.scaleX(100))); + _availableList.setViewStyleOption(LVS_EX_CHECKBOXES); _availableList.initView(_hInst, _hSelf); - ListView_SetBkColor(_availableList.getViewHwnd(), bgColor); ListView_SetTextBkColor(_availableList.getViewHwnd(), bgColor); ListView_SetTextColor(_availableList.getViewHwnd(), fgColor); - _availableList.reSizeView(listRect); _updateList.addColumn(columnInfo(pluginStr, nppParam._dpiManager.scaleX(200))); _updateList.addColumn(columnInfo(vesionStr, nppParam._dpiManager.scaleX(100))); - //_updateList.addColumn(columnInfo(stabilityStr, nppParam._dpiManager.scaleX(70))); _updateList.setViewStyleOption(LVS_EX_CHECKBOXES); - _updateList.initView(_hInst, _hSelf); - ListView_SetBkColor(_updateList.getViewHwnd(), bgColor); ListView_SetTextBkColor(_updateList.getViewHwnd(), bgColor); ListView_SetTextColor(_updateList.getViewHwnd(), fgColor); - _updateList.reSizeView(listRect); _installedList.addColumn(columnInfo(pluginStr, nppParam._dpiManager.scaleX(200))); _installedList.addColumn(columnInfo(vesionStr, nppParam._dpiManager.scaleX(100))); - //_installedList.addColumn(columnInfo(stabilityStr, nppParam._dpiManager.scaleX(70))); _installedList.setViewStyleOption(LVS_EX_CHECKBOXES); - _installedList.initView(_hInst, _hSelf); - ListView_SetBkColor(_installedList.getViewHwnd(), bgColor); ListView_SetTextBkColor(_installedList.getViewHwnd(), bgColor); ListView_SetTextColor(_installedList.getViewHwnd(), fgColor); - _installedList.reSizeView(listRect); + _incompatibleList.addColumn(columnInfo(pluginStr, nppParam._dpiManager.scaleX(200))); + _incompatibleList.addColumn(columnInfo(vesionStr, nppParam._dpiManager.scaleX(100))); + _incompatibleList.initView(_hInst, _hSelf); + ListView_SetBkColor(_incompatibleList.getViewHwnd(), bgColor); + ListView_SetTextBkColor(_incompatibleList.getViewHwnd(), bgColor); + ListView_SetTextColor(_incompatibleList.getViewHwnd(), fgColor); + _incompatibleList.reSizeView(listRect); + + HWND hDesc = ::GetDlgItem(_hSelf, IDC_PLUGINADM_EDIT); ::MoveWindow(hDesc, descRect.left, descRect.top, descRect.right, descRect.bottom, TRUE); ::InvalidateRect(hDesc, nullptr, TRUE); @@ -466,6 +464,7 @@ void PluginsAdminDlg::changeColumnName(COLUMN_TYPE index, const TCHAR *name2chan _availableList.changeColumnName(index, name2change); _updateList.changeColumnName(index, name2change); _installedList.changeColumnName(index, name2change); + _incompatibleList.changeColumnName(index, name2change); } void PluginViewList::changeColumnName(COLUMN_TYPE index, const TCHAR *name2change) @@ -788,6 +787,9 @@ bool PluginsAdminDlg::updateList() // initialize update list view checkUpdates(); + // initialize incompatible list view + initIncompatiblePluginList(); + // initialize installed list view loadFromPluginInfos(); @@ -823,6 +825,30 @@ bool PluginsAdminDlg::initAvailablePluginsViewFromList() return true; } + +bool PluginsAdminDlg::initIncompatiblePluginList() +{ + TCHAR nppFullPathName[MAX_PATH]; + GetModuleFileName(NULL, nppFullPathName, MAX_PATH); + + Version nppVer; + nppVer.setVersionFrom(nppFullPathName); + + for (const auto& i : _incompatibleList._list) + { + vector values2Add; + values2Add.push_back(i->_displayName); + Version v = i->_version; + values2Add.push_back(v.toString()); + + // add in order + size_t j = _incompatibleList._ui.findAlphabeticalOrderPos(i->_displayName, _incompatibleList._sortType == DISPLAY_NAME_ALPHABET_ENCREASE ? ListView::sortEncrease : ListView::sortDecrease); + _incompatibleList._ui.addLine(values2Add, reinterpret_cast(i), static_cast(j)); + } + + return true; +} + bool PluginsAdminDlg::loadFromPluginInfos() { if (!_pPluginsManager) @@ -868,6 +894,27 @@ bool PluginsAdminDlg::loadFromPluginInfos() } } + // Search from unloaded incompatible plugins + for (size_t j = 0, nb = _incompatibleList.nbItem(); j < nb; j++) + { + PluginUpdateInfo* incompatiblePluginInfo = _incompatibleList.getPluginInfoFromUiIndex(j); + int listIndex; + PluginUpdateInfo* foundInfoOfAvailable = _availableList.findPluginInfoFromFolderName(incompatiblePluginInfo->_folderName, listIndex); + + if (foundInfoOfAvailable) + { + // if the incompatible plugin version is smaller than the one on the available list, put it in the update list + if (foundInfoOfAvailable->_version > incompatiblePluginInfo->_version) + { + // Hide it from the available list + _availableList.hideFromListIndex(listIndex); + + PluginUpdateInfo* pui = new PluginUpdateInfo(*foundInfoOfAvailable); + _updateList.pushBack(pui); + } + } + } + return true; } @@ -1024,7 +1071,7 @@ bool PluginsAdminDlg::searchInPlugins(bool isNextMode) const void PluginsAdminDlg::switchDialog(int indexToSwitch) { generic_string desc; - bool showAvailable, showUpdate, showInstalled; + bool showAvailable, showUpdate, showInstalled, showIncompatibile; switch (indexToSwitch) { case 0: // available plugins @@ -1032,6 +1079,7 @@ void PluginsAdminDlg::switchDialog(int indexToSwitch) showAvailable = true; showUpdate = false; showInstalled = false; + showIncompatibile = false; long infoIndex = _availableList.getSelectedIndex(); if (infoIndex != -1 && infoIndex < static_cast(_availableList.nbItem())) @@ -1044,6 +1092,7 @@ void PluginsAdminDlg::switchDialog(int indexToSwitch) showAvailable = false; showUpdate = true; showInstalled = false; + showIncompatibile = false; long infoIndex = _updateList.getSelectedIndex(); if (infoIndex != -1 && infoIndex < static_cast(_updateList.nbItem())) @@ -1056,6 +1105,7 @@ void PluginsAdminDlg::switchDialog(int indexToSwitch) showAvailable = false; showUpdate = false; showInstalled = true; + showIncompatibile = false; long infoIndex = _installedList.getSelectedIndex(); if (infoIndex != -1 && infoIndex < static_cast(_installedList.nbItem())) @@ -1063,6 +1113,19 @@ void PluginsAdminDlg::switchDialog(int indexToSwitch) } break; + case 3: // incompability plugins + { + showAvailable = false; + showUpdate = false; + showInstalled = false; + showIncompatibile = true; + + long infoIndex = _incompatibleList.getSelectedIndex(); + if (infoIndex != -1 && infoIndex < static_cast(_incompatibleList.nbItem())) + desc = _incompatibleList.getPluginInfoFromUiIndex(infoIndex)->_description; + } + break; + default: return; } @@ -1070,6 +1133,7 @@ void PluginsAdminDlg::switchDialog(int indexToSwitch) _availableList.displayView(showAvailable); _updateList.displayView(showUpdate); _installedList.displayView(showInstalled); + _incompatibleList.displayView(showIncompatibile); ::SetDlgItemText(_hSelf, IDC_PLUGINADM_EDIT, desc.c_str()); @@ -1219,7 +1283,8 @@ intptr_t CALLBACK PluginsAdminDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR } else if (pnmh->hwndFrom == _availableList.getViewHwnd() || pnmh->hwndFrom == _updateList.getViewHwnd() || - pnmh->hwndFrom == _installedList.getViewHwnd()) + pnmh->hwndFrom == _installedList.getViewHwnd() || + pnmh->hwndFrom == _incompatibleList.getViewHwnd()) { PluginViewList* pViewList; int buttonID; @@ -1234,11 +1299,16 @@ intptr_t CALLBACK PluginsAdminDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR pViewList = &_updateList; buttonID = IDC_PLUGINADM_UPDATE; } - else // pnmh->hwndFrom == _installedList.getViewHwnd() + else if (pnmh->hwndFrom == _installedList.getViewHwnd()) { pViewList = &_installedList; buttonID = IDC_PLUGINADM_REMOVE; } + else // pnmh->hwndFrom == _incompatibleList.getViewHwnd() + { + pViewList = &_incompatibleList; + buttonID = 0; + } LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; @@ -1249,16 +1319,19 @@ intptr_t CALLBACK PluginsAdminDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR if ((pnmv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2) || // checked (pnmv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(1)) // unchecked { - HWND hButton = ::GetDlgItem(_hSelf, buttonID); - vector checkedArray = pViewList->getCheckedIndexes(); - bool showButton = checkedArray.size() > 0; + if (buttonID) + { + HWND hButton = ::GetDlgItem(_hSelf, buttonID); + vector checkedArray = pViewList->getCheckedIndexes(); + bool showButton = checkedArray.size() > 0; - ::EnableWindow(hButton, showButton); + ::EnableWindow(hButton, showButton); + } } else if (pnmv->uNewState & LVIS_SELECTED) { PluginUpdateInfo* pui = pViewList->getPluginInfoFromUiIndex(pnmv->iItem); - generic_string desc = pui->describe(); + generic_string desc = buttonID ? pui->describe() : pui->_description; ::SetDlgItemText(_hSelf, IDC_PLUGINADM_EDIT, desc.c_str()); } } diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h index d92c9beaf..3c2fbf8a1 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h @@ -128,6 +128,7 @@ public: void changeColumnName(COLUMN_TYPE index, const TCHAR *name2change); private: + // _list & _ui should keep being synchronized std::vector _list; ListView _ui; @@ -180,6 +181,10 @@ public : const PluginViewList & getAvailablePluginUpdateInfoList() const { return _availableList; }; + + PluginViewList & getIncompatibleList() { + return _incompatibleList; + }; protected: virtual intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam); @@ -191,9 +196,10 @@ private : TabBar _tab; - PluginViewList _availableList; // A permanent list, once it's loaded (no removal - only hide or show) - PluginViewList _updateList; // A dynamical list, items are removable - PluginViewList _installedList; // A dynamical list, items are removable + PluginViewList _availableList; // A permanent list, once it's loaded (no removal - only hide or show) + PluginViewList _updateList; // A dynamical list, items are removable + PluginViewList _installedList; // A dynamical list, items are removable + PluginViewList _incompatibleList; // A permanent list, once it's loaded (no removal - only hide or show) PluginsManager *_pPluginsManager = nullptr; NppCurrentStatus _nppCurrentStatus; @@ -213,6 +219,7 @@ private : }; bool initAvailablePluginsViewFromList(); + bool initIncompatiblePluginList(); bool loadFromPluginInfos(); bool checkUpdates();