1 /////////////////////////////////////////////////////////////////////////////
2 // WinMerge: an interactive diff/merge utility
3 // Copyright (C) 1997-2000 Thingamahoochie Software
5 // SPDX-License-Identifier: GPL-2.0-or-later
6 /////////////////////////////////////////////////////////////////////////////
8 * @file SelectPluginDlg.cpp
10 * @brief Unpacker plugin selection dialog implementation.
14 #include "SelectPluginDlg.h"
16 #include "FileTransform.h"
17 #include "OptionsMgr.h"
18 #include "OptionsDef.h"
25 /////////////////////////////////////////////////////////////////////////////
26 // CSelectPluginDlg dialog
28 void CSelectPluginDlg::Initialize(bool unpacker)
30 //{{AFX_DATA_INIT(CSelectPluginDlg)
31 m_bNoExtensionCheck = false;
32 m_bOpenInSameFrameType = false;
33 m_strDescription = _T("");
34 m_strExtensions = _T("");
35 m_strArguments = _T("");
38 // texts for the default unpackers
39 noPlugin.reset(new PluginInfo);
40 noPlugin->m_lpDispatch = nullptr;
41 noPlugin->m_name = _("<None>");
42 automaticPlugin.reset(new PluginInfo);
43 automaticPlugin->m_lpDispatch = nullptr;
44 automaticPlugin->m_name = _("<Automatic>");
45 automaticPlugin->m_description = _("The adapted unpacker is applied to both files (one file only needs the extension).");
47 std::vector<std::wstring> events = unpacker ? FileTransform::UnpackerEventNames : FileTransform::PredifferEventNames;
48 m_Plugins = FileTransform::CreatePluginMenuInfos(m_filteredFilenames, events, 0).second;
52 CSelectPluginDlg::CSelectPluginDlg(const String& pluginPipeline, const String& filename,
53 bool unpacker /*= true */, bool argumentRequired/*= false */, CWnd* pParent /*= nullptr*/)
54 : CTrDialog(CSelectPluginDlg::IDD, pParent)
55 , m_strPluginPipeline(pluginPipeline)
56 , m_filteredFilenames(filename)
57 , m_bUnpacker(unpacker)
58 , m_bArgumentRequired(argumentRequired)
63 CSelectPluginDlg::~CSelectPluginDlg()
67 void CSelectPluginDlg::DoDataExchange(CDataExchange* pDX)
69 CTrDialog::DoDataExchange(pDX);
70 //{{AFX_DATA_MAP(CSelectPluginDlg)
71 DDX_Control(pDX, IDC_PLUGIN_NAME, m_cboPluginName);
72 DDX_Check(pDX, IDC_PLUGIN_ALLOW_ALL, m_bNoExtensionCheck);
73 DDX_Check(pDX, IDC_PLUGIN_OPEN_IN_SAME_FRAME_TYPE, m_bOpenInSameFrameType);
74 DDX_Text(pDX, IDC_PLUGIN_DESCRIPTION, m_strDescription);
75 DDX_Text(pDX, IDC_PLUGIN_SUPPORTED_EXTENSIONS, m_strExtensions);
76 DDX_Text(pDX, IDC_PLUGIN_ARGUMENTS, m_strArguments);
77 DDX_Control(pDX, IDC_PLUGIN_PIPELINE, m_ctlPluginPipeline);
78 DDX_CBStringExact(pDX, IDC_PLUGIN_PIPELINE, m_strPluginPipeline);
83 BEGIN_MESSAGE_MAP(CSelectPluginDlg, CTrDialog)
84 //{{AFX_MSG_MAP(CSelectPluginDlg)
85 ON_BN_CLICKED(IDC_PLUGIN_ALLOW_ALL, OnUnpackerAllowAll)
86 ON_CBN_SELCHANGE(IDC_PLUGIN_NAME, OnSelchangeUnpackerName)
87 ON_CBN_SELENDOK(IDC_PLUGIN_NAME, OnSelchangeUnpackerName)
88 ON_BN_CLICKED(IDC_PLUGIN_ADDPIPE, OnClickedAddPipe)
89 ON_EN_CHANGE(IDC_PLUGIN_PIPELINE, OnChangePipeline)
93 /////////////////////////////////////////////////////////////////////////////
94 // CSelectPluginDlg message handlers
96 void CSelectPluginDlg::OnOK()
100 GetOptionsMgr()->SaveOption(OPT_PLUGINS_UNPACK_DONT_CHECK_EXTENSION, m_bNoExtensionCheck);
101 GetOptionsMgr()->SaveOption(OPT_PLUGINS_OPEN_IN_SAME_FRAME_TYPE, m_bOpenInSameFrameType);
102 m_ctlPluginPipeline.SaveState(m_bUnpacker ? _T("Files\\Unpacker") : _T("Files\\Prediffer"));
107 BOOL CSelectPluginDlg::OnInitDialog()
109 CTrDialog::OnInitDialog();
111 m_bNoExtensionCheck = GetOptionsMgr()->GetBool(OPT_PLUGINS_UNPACK_DONT_CHECK_EXTENSION);
112 m_bOpenInSameFrameType = GetOptionsMgr()->GetBool(OPT_PLUGINS_OPEN_IN_SAME_FRAME_TYPE);
115 m_ctlPluginPipeline.SetFileControlStates(true);
116 m_ctlPluginPipeline.LoadState(m_bUnpacker ? _T("Files\\Unpacker") : _T("Files\\Prediffer"));
118 EnableDlgItem(IDC_PLUGIN_OPEN_IN_SAME_FRAME_TYPE, m_bUnpacker);
122 if (m_bArgumentRequired)
124 SetWindowText(_("Specify plugin arguments").c_str());
127 GetDlgItemText(IDC_PLUGIN_ARGUMENTS, args);
128 m_ctlPluginPipeline.GetWindowText(pipeline);
129 m_strPluginPipeline = pipeline + _T(" ") + args.c_str();
130 m_ctlPluginPipeline.SetWindowText(m_strPluginPipeline.c_str());
131 m_ctlPluginPipeline.SetFocus();
135 return TRUE; // return TRUE unless you set the focus to a control
136 // EXCEPTION: OCX Property Pages should return FALSE
139 void CSelectPluginDlg::prepareListbox()
144 auto parseResult = PluginForFile::ParsePluginPipeline(m_strPluginPipeline, errorMessage);
145 String lastPluginName = parseResult.empty() ? _T("") : parseResult.back().name;
146 m_cboPluginName.AddString(noPlugin->m_name.c_str());
147 m_cboPluginName.AddString(automaticPlugin->m_name.c_str());
149 std::vector<String> processTypes;
150 for (const auto& [processType, pluginList] : m_Plugins)
151 processTypes.push_back(processType);
153 auto itFound = std::find(processTypes.begin(), processTypes.end(), _("&Others"));
154 if (itFound != processTypes.end())
156 processTypes.erase(itFound);
157 processTypes.push_back(_("&Others"));
160 for (const auto& processType : processTypes)
162 const auto& pluginList = m_Plugins[processType];
163 String processType2 = processType;
164 auto it = processType2.find(_("(&"));
165 if (it != String::npos)
166 processType2.erase(it, it + 2);
167 strutils::replace(processType2, _T("&"), _T(""));
168 if (!processType2.empty())
169 m_cboPluginName.AddString((_T("[") + processType2 + _T("]")).c_str());
170 for (const auto& [caption, name, id, plugin] : pluginList)
172 if (!name.empty() && name != _T("<Automatic>"))
174 if (m_bNoExtensionCheck || plugin->TestAgainstRegList(m_filteredFilenames) || lastPluginName == name)
176 m_cboPluginName.AddString(name.c_str());
177 if (lastPluginName == name)
178 sel = m_cboPluginName.GetCount() - 1;
183 if (lastPluginName == _T("<Automatic>"))
187 m_cboPluginName.SelectString(-1, noPlugin->m_name.c_str());
191 m_cboPluginName.SetCurSel(sel);
192 OnSelchangeUnpackerName();
196 void CSelectPluginDlg::OnUnpackerAllowAll()
200 m_cboPluginName.ResetContent();
207 void CSelectPluginDlg::OnClickedAddPipe()
209 m_strPluginPipeline += _T("|");
213 void CSelectPluginDlg::OnChangePipeline()
218 void CSelectPluginDlg::OnSelchangeUnpackerName()
220 PluginInfo* pPlugin = nullptr;
221 int i = m_cboPluginName.GetCurSel();
224 pPlugin = noPlugin.get();
225 m_strPluginPipeline.clear();
229 pPlugin = automaticPlugin.get();
230 m_strPluginPipeline = _T("<Automatic>");
234 // initialize with the default unpacker
235 CString cstrPluginName;
236 m_cboPluginName.GetWindowText(cstrPluginName);
237 String pluginName = cstrPluginName.Trim();
238 for (const auto& [processType, pluginList] : m_Plugins)
240 for (const auto& [caption, name, id, plugin] : pluginList)
242 if (pluginName == name)
244 String pluginPipeline = strutils::trim_ws(m_strPluginPipeline);
245 if (!pluginPipeline.empty() && pluginPipeline.back() == '|')
246 pluginPipeline += _T("dummy");
248 auto parseResult = PluginForFile::ParsePluginPipeline(pluginPipeline, errorMessage);
249 if (parseResult.empty())
250 parseResult.push_back({ name, {}, '\0' });
251 parseResult.back().name = name;
252 m_strPluginPipeline = PluginForFile::MakePluginPipeline(parseResult);
262 m_strDescription = pPlugin->m_description;
263 m_strExtensions = pPlugin->m_filtersText;
264 m_strArguments = pPlugin->m_arguments;
267 m_bOpenInSameFrameType = IsDlgButtonChecked(IDC_PLUGIN_OPEN_IN_SAME_FRAME_TYPE);