From 5a94263beee310065df1aaf40ba257ab07658173 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Tue, 6 Sep 2022 05:10:22 +0200 Subject: [PATCH] Add incompatible (unloaded) plugin list in Plugin Admin The plugins which are not compatible but their newer versions are available are not only on the incompatible list, but also on the Updates list. Fix #12069, close #12105 --- .../MISC/PluginsManager/PluginsManager.cpp | 45 ++++++- .../src/MISC/PluginsManager/PluginsManager.h | 11 +- PowerEditor/src/Notepad_plus.cpp | 2 +- .../WinControls/PluginsAdmin/pluginsAdmin.cpp | 121 ++++++++++++++---- .../WinControls/PluginsAdmin/pluginsAdmin.h | 13 +- 5 files changed, 156 insertions(+), 36 deletions(-) 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();