OSDN Git Service

Improve plugin system (#797)
[winmerge-jp/winmerge-jp.git] / Src / PluginsListDlg.cpp
1 /**
2  * @file  PluginsListDlg.cpp
3  *
4  * @brief Implementation file for PluginsList dialog
5  */
6
7 #include "stdafx.h"
8 #include "PluginsListDlg.h"
9 #include "WildcardDropList.h"
10 #include "UnicodeString.h"
11 #include "Plugins.h"
12 #include "OptionsDef.h"
13 #include "OptionsMgr.h"
14 #include "Merge.h"
15
16 /** @brief Location for plugins specific help to open. */
17 static TCHAR PluginsHelpLocation[] = _T("::/htmlhelp/Plugins.html");
18
19 IMPLEMENT_DYNAMIC(PluginsListDlg, CTrDialog)
20
21 BEGIN_MESSAGE_MAP(PluginsListDlg, CTrDialog)
22         ON_BN_CLICKED(IDOK, OnBnClickedOk)
23         ON_BN_CLICKED(IDC_PLUGIN_SETTINGS, OnBnClickedPluginSettings)
24         ON_BN_CLICKED(IDC_PLUGIN_DEFAULTS, OnBnClickedFileFiltesDefaults)
25         ON_CBN_DROPDOWN(IDC_PLUGIN_FILEFILTERS, OnDropDownPatterns)
26         ON_CBN_CLOSEUP(IDC_PLUGIN_FILEFILTERS, OnCloseUpPatterns)
27         ON_NOTIFY(NM_DBLCLK, IDC_PLUGINSLIST_LIST, OnNMDblclkList)
28         ON_NOTIFY(LVN_ITEMCHANGING, IDC_PLUGINSLIST_LIST, OnLVNItemChanging)
29         ON_NOTIFY(LVN_ITEMCHANGED, IDC_PLUGINSLIST_LIST, OnLVNItemChanged)
30         ON_COMMAND(ID_HELP, OnHelp)
31 END_MESSAGE_MAP()
32
33 /**
34  * @brief Constructor.
35  */
36 PluginsListDlg::PluginsListDlg(CWnd* pParent /*= nullptr*/)
37         : CTrDialog(PluginsListDlg::IDD, pParent)
38 {
39 }
40
41 /**
42  * @brief Destructor.
43  */
44 PluginsListDlg::~PluginsListDlg()
45 {
46 }
47
48 void PluginsListDlg::DoDataExchange(CDataExchange* pDX)
49 {
50         CTrDialog::DoDataExchange(pDX);
51         DDX_Control(pDX, IDC_PLUGINSLIST_LIST, m_list);
52         DDX_Control(pDX, IDC_PLUGIN_FILEFILTERS, m_comboPatterns);
53 }
54
55 /**
56  * @brief Initialize the dialog.
57  */
58 BOOL PluginsListDlg::OnInitDialog()
59 {
60         CTrDialog::OnInitDialog();
61         
62         InitList();
63         AddPlugins();
64         m_list.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
65
66         CheckDlgButton(IDC_PLUGINS_ENABLE, 
67                 GetOptionsMgr()->GetBool(OPT_PLUGINS_ENABLED) ? BST_CHECKED : BST_UNCHECKED);
68
69         return FALSE;  // return TRUE unless you set the focus to a control
70                       // EXCEPTION: OCX Property Pages should return FALSE
71 }
72
73 /**
74  * @brief Set-up the list control.
75  */
76 void PluginsListDlg::InitList()
77 {
78         // Show selection across entire row.
79         // Also enable infotips.
80         m_list.SetExtendedStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
81
82         const int lpx = CClientDC(this).GetDeviceCaps(LOGPIXELSX);
83         auto pointToPixel = [lpx](int point) { return MulDiv(point, lpx, 72); };
84
85         String title = _("Name");
86         m_list.InsertColumn(0, title.c_str(), LVCFMT_LEFT, pointToPixel(150));
87         title = _("Type");
88         m_list.InsertColumn(1, title.c_str(), LVCFMT_LEFT, pointToPixel(75));
89         title = _("Description");
90         m_list.InsertColumn(2, title.c_str(), LVCFMT_LEFT, pointToPixel(225));
91 }
92
93 /**
94  * @brief Add found plugins to the list.
95  */
96 void PluginsListDlg::AddPlugins()
97 {
98         String type = _("Unpacker");
99         AddPluginsToList(L"FILE_FOLDER_PACK_UNPACK", type);
100         AddPluginsToList(L"FILE_PACK_UNPACK", type);
101         AddPluginsToList(L"BUFFER_PACK_UNPACK", type);
102         type = _("Prediffer");
103         AddPluginsToList(L"FILE_PREDIFF", type);
104         AddPluginsToList(L"BUFFER_PREDIFF", type);
105         type = _("Editor script");
106         AddPluginsToList(L"EDITOR_SCRIPT", type);
107 }
108
109 /**
110  * @brief Add plugins of given event type to the list.
111  * @param [in] pluginEvent Event type for plugins to add.
112  * @param [in] pluginType String to use as type in the list.
113  */
114 void PluginsListDlg::AddPluginsToList(const wchar_t *pluginEvent, const String& pluginType)
115 {
116         PluginArray * piPluginArray = 
117                 CAllThreadsScripts::GetActiveSet()->GetAvailableScripts(pluginEvent);
118
119         for (size_t iPlugin = 0 ; iPlugin < piPluginArray->size() ; iPlugin++)
120         {
121                 const PluginInfoPtr& plugin = piPluginArray->at(iPlugin);
122                 int ind = m_list.InsertItem(m_list.GetItemCount(), plugin->m_name.c_str());
123                 m_list.SetItemText(ind, 1, pluginType.c_str());
124                 m_list.SetItemText(ind, 2, plugin->m_description.c_str());
125                 m_list.SetCheck(ind, !plugin->m_disabled);
126                 m_list.SetItemData(ind, reinterpret_cast<DWORD_PTR>(plugin.get()));
127         }
128 }
129
130 PluginInfo *PluginsListDlg::GetSelectedPluginInfo() const
131 {
132         int ind = m_list.GetNextItem(-1, LVNI_SELECTED);
133         if (ind < 0)
134                 return nullptr;
135         return reinterpret_cast<PluginInfo *>(m_list.GetItemData(ind));
136 }
137
138 /**
139  * @brief Save plugins enabled setting when closing the dialog.
140  */
141 void PluginsListDlg::OnBnClickedOk()
142 {
143         GetOptionsMgr()->SaveOption(OPT_PLUGINS_ENABLED, 
144                 (IsDlgButtonChecked(IDC_PLUGINS_ENABLE) == 1));
145
146         OnLVNItemChanging(nullptr, nullptr);
147
148         for (int i = 0; i < m_list.GetItemCount(); ++i)
149         {
150                 PluginInfo * plugin = CAllThreadsScripts::GetActiveSet()->GetPluginByName(nullptr, String(m_list.GetItemText(i, 0)));
151                 plugin->m_disabled = !m_list.GetCheck(i);
152         }
153
154         CAllThreadsScripts::GetActiveSet()->SaveSettings();
155         CAllThreadsScripts::ReloadCustomSettings();
156         OnOK();
157 }
158
159 void PluginsListDlg::OnBnClickedPluginSettings()
160 {
161         POSITION pos = m_list.GetFirstSelectedItemPosition();
162         if (pos != nullptr)
163         {
164                 String pluginName = static_cast<const TCHAR *>(m_list.GetItemText(m_list.GetNextSelectedItem(pos), 0));
165                 for (int i = 0; TransformationCategories[i] != nullptr; ++i)
166                 {
167                         PluginInfo * plugin = CAllThreadsScripts::GetActiveSet()->GetPluginByName(TransformationCategories[i], pluginName);
168                         if (plugin != nullptr)
169                         {
170                                 EnableWindow(false);
171                                 plugin::InvokeShowSettingsDialog(plugin->m_lpDispatch);
172                                 EnableWindow(true);
173                                 SetForegroundWindow();
174                                 break;
175                         }
176                 }
177         }
178 }
179
180 void PluginsListDlg::OnBnClickedFileFiltesDefaults()
181 {
182         PluginInfo *plugin = GetSelectedPluginInfo();
183         if (plugin)
184         {
185                 SetDlgItemText(IDC_PLUGIN_FILEFILTERS, plugin->m_filtersTextDefault);
186                 SetDlgItemText(IDC_PLUGIN_ARGUMENTS, plugin->m_argumentsDefault);
187                 CheckDlgButton(IDC_PLUGIN_AUTOMATIC, plugin->m_bAutomaticDefault);
188         }
189 }
190
191 void PluginsListDlg::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
192 {
193         OnBnClickedPluginSettings();
194 }
195
196 void PluginsListDlg::OnLVNItemChanging(NMHDR *pNMHDR, LRESULT *pResult)
197 {
198         PluginInfo *plugin = GetSelectedPluginInfo();
199         if (plugin)
200         {
201                 GetDlgItemText(IDC_PLUGIN_FILEFILTERS, plugin->m_filtersText);
202                 WildcardRemoveDuplicatePatterns(plugin->m_filtersText);
203                 plugin->LoadFilterString();
204                 GetDlgItemText(IDC_PLUGIN_ARGUMENTS, plugin->m_arguments);
205                 plugin->m_bAutomatic = !!IsDlgButtonChecked(IDC_PLUGIN_AUTOMATIC);
206         }
207 }
208
209 void PluginsListDlg::OnLVNItemChanged(NMHDR *pNMHDR, LRESULT *pResult)
210 {
211         PluginInfo *plugin = GetSelectedPluginInfo();
212         if (plugin)
213         {
214                 SetDlgItemText(IDC_PLUGIN_FILEFILTERS, plugin->m_filtersText);
215                 SetDlgItemText(IDC_PLUGIN_ARGUMENTS, plugin->m_arguments);
216                 CheckDlgButton(IDC_PLUGIN_AUTOMATIC, plugin->m_bAutomatic);
217         }
218 }
219
220 /**
221  * @brief Prepares multi-selection drop list 
222  */
223 void PluginsListDlg::OnDropDownPatterns()
224 {
225         PluginInfo *plugin = GetSelectedPluginInfo();
226         if (plugin)
227         {
228                 String patterns = plugin->m_filtersTextDefault;
229                 WildcardDropList::OnDropDown(m_comboPatterns, 3, patterns.c_str());
230         }
231 }
232
233 /**
234  * @brief Finishes drop list multi-selection
235  */
236 void PluginsListDlg::OnCloseUpPatterns()
237 {
238         WildcardDropList::OnCloseUp(m_comboPatterns);
239 }
240
241 /**
242  * @brief Open help from mainframe when user presses F1.
243  */
244 void PluginsListDlg::OnHelp()
245 {
246         theApp.ShowHelp(PluginsHelpLocation);
247 }
248