1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include <swl.h>
8 #include "fileassociations.h"
9 #include "string-util.h"
10 #include "wcm-config.h"
11 #include "ltext.h"
12 #include "strconfig.h"
13 #include "unicode_lc.h"
14 #include "dialog_enums.h"
15 #include "dialog_helpers.h"
16 
17 /// dialog to edit a single file association
18 class clEditFileAssociationsWin: public NCVertDialog
19 {
20 public:
clEditFileAssociationsWin(NCDialogParent * parent,const clNCFileAssociation * Assoc)21 	clEditFileAssociationsWin( NCDialogParent* parent, const clNCFileAssociation* Assoc )
22 		: NCVertDialog( ::createDialogAsChild, 0, parent, utf8_to_unicode( _LT( "Edit file associations" ) ).data(), bListOkCancel )
23 		, m_Layout( 17, 2 )
24 		, m_MaskText( 0, this, utf8_to_unicode( _LT( "A file &mask or several file masks (separated with commas)" ) ).data(), &m_MaskEdit )
25 		, m_MaskEdit( 0, this, 0, 0, 16 )
26 		, m_DescriptionText( 0, this, utf8_to_unicode( _LT( "&Description of the file association" ) ).data(), &m_DescriptionEdit )
27 		, m_DescriptionEdit( 0, this, 0, 0, 16 )
28 		, m_HasTerminalButton( 0, this, utf8_to_unicode( _LT( "Start in &this terminal" ) ).data(), 0, true )
29 		, m_ExecuteCommandText( 0, this, utf8_to_unicode( _LT( "E&xecute command (used for Enter)" ) ).data(), &m_ExecuteCommandEdit )
30 		, m_ExecuteCommandEdit( 0, this, 0, 0, 16 )
31 		, m_ExecuteCommandSecondaryText( 0, this, utf8_to_unicode( _LT( "Execute command (used for Ctrl+&PgDn)" ) ).data(), &m_ExecuteCommandSecondaryEdit )
32 		, m_ExecuteCommandSecondaryEdit( 0, this, 0, 0, 16 )
33 		, m_ViewCommandText( 0, this, utf8_to_unicode( _LT( "&View command (used for F3)" ) ).data(), &m_ViewCommandEdit )
34 		, m_ViewCommandEdit( 0, this, 0, 0, 16 )
35 		, m_ViewCommandSecondaryText( 0, this, utf8_to_unicode( _LT( "View command (used for Alt+F&3)" ) ).data(), &m_ViewCommandSecondaryEdit )
36 		, m_ViewCommandSecondaryEdit( 0, this, 0, 0, 16 )
37 		, m_EditCommandText( 0, this, utf8_to_unicode( _LT( "&Edit command (used for F4)" ) ).data(), &m_EditCommandEdit )
38 		, m_EditCommandEdit( 0, this, 0, 0, 16 )
39 		, m_EditCommandSecondaryText( 0, this, utf8_to_unicode( _LT( "Edit command (used for Alt+F&4)" ) ).data(), &m_EditCommandSecondaryEdit )
40 		, m_EditCommandSecondaryEdit( 0, this, 0, 0, 16 )
41 	{
42 		m_MaskEdit.SetText( utf8_to_unicode( "*" ).data(), true );
43 
44 		if ( Assoc )
45 		{
46 			m_MaskEdit.SetText( Assoc->GetMask().data(), false );
47 			m_DescriptionEdit.SetText( Assoc->GetDescription().data(), false );
48 			m_HasTerminalButton.Change( Assoc->GetHasTerminal() );
49 			m_ExecuteCommandEdit.SetText( Assoc->GetExecuteCommand().data(), false );
50 			m_ExecuteCommandSecondaryEdit.SetText( Assoc->GetExecuteCommandSecondary().data(), false );
51 			m_ViewCommandEdit.SetText( Assoc->GetViewCommand().data(), false );
52 			m_ViewCommandSecondaryEdit.SetText( Assoc->GetViewCommandSecondary().data(), false );
53 			m_EditCommandEdit.SetText( Assoc->GetEditCommand().data(), false );
54 			m_EditCommandSecondaryEdit.SetText( Assoc->GetEditCommandSecondary().data(), false );
55 		}
56 
57 		m_Layout.AddWinAndEnable( &m_MaskText, 0, 0 );
58 		m_Layout.AddWinAndEnable( &m_MaskEdit, 1, 0 );
59 		m_Layout.AddWinAndEnable( &m_DescriptionText, 2, 0 );
60 		m_Layout.AddWinAndEnable( &m_DescriptionEdit, 3, 0 );
61 		m_Layout.AddWinAndEnable( &m_HasTerminalButton, 4, 0 );
62 		m_Layout.AddWinAndEnable( &m_ExecuteCommandText, 5, 0 );
63 		m_Layout.AddWinAndEnable( &m_ExecuteCommandEdit, 6, 0 );
64 		m_Layout.AddWinAndEnable( &m_ExecuteCommandSecondaryText, 7, 0 );
65 		m_Layout.AddWinAndEnable( &m_ExecuteCommandSecondaryEdit, 8, 0 );
66 		m_Layout.AddWinAndEnable( &m_ViewCommandText, 9, 0 );
67 		m_Layout.AddWinAndEnable( &m_ViewCommandEdit, 10, 0 );
68 		m_Layout.AddWinAndEnable( &m_ViewCommandSecondaryText, 11, 0 );
69 		m_Layout.AddWinAndEnable( &m_ViewCommandSecondaryEdit, 12, 0 );
70 		m_Layout.AddWinAndEnable( &m_EditCommandText, 13, 0 );
71 		m_Layout.AddWinAndEnable( &m_EditCommandEdit, 14, 0 );
72 		m_Layout.AddWinAndEnable( &m_EditCommandSecondaryText, 15, 0 );
73 		m_Layout.AddWinAndEnable( &m_EditCommandSecondaryEdit, 16, 0 );
74 
75 		AddLayout( &m_Layout );
76 
77 		order.append( &m_MaskEdit );
78 		order.append( &m_DescriptionEdit );
79 		order.append( &m_HasTerminalButton );
80 		order.append( &m_ExecuteCommandEdit );
81 		order.append( &m_ExecuteCommandSecondaryEdit );
82 		order.append( &m_ViewCommandEdit );
83 		order.append( &m_ViewCommandSecondaryEdit );
84 		order.append( &m_EditCommandEdit );
85 		order.append( &m_EditCommandSecondaryEdit );
86 
87 		SetPosition();
88 	}
89 
GetMask() const90 	std::vector<unicode_t> GetMask() const { return m_MaskEdit.GetText(); }
GetDescription() const91 	std::vector<unicode_t> GetDescription() const { return m_DescriptionEdit.GetText(); }
GetExecuteCommand() const92 	std::vector<unicode_t> GetExecuteCommand() const { return m_ExecuteCommandEdit.GetText(); }
GetExecuteCommandSecondary() const93 	std::vector<unicode_t> GetExecuteCommandSecondary() const { return m_ExecuteCommandSecondaryEdit.GetText(); }
GetViewCommand() const94 	std::vector<unicode_t> GetViewCommand() const { return m_ViewCommandEdit.GetText(); }
GetViewCommandSecondary() const95 	std::vector<unicode_t> GetViewCommandSecondary() const { return m_ViewCommandSecondaryEdit.GetText(); }
GetEditCommand() const96 	std::vector<unicode_t> GetEditCommand() const { return m_EditCommandEdit.GetText(); }
GetEditCommandSecondary() const97 	std::vector<unicode_t> GetEditCommandSecondary() const { return m_EditCommandSecondaryEdit.GetText(); }
98 
GetResult() const99 	const clNCFileAssociation& GetResult() const
100 	{
101 		m_Result.SetMask( GetMask() );
102 		m_Result.SetDescription( GetDescription() );
103 		m_Result.SetExecuteCommand( GetExecuteCommand() );
104 		m_Result.SetExecuteCommandSecondary( GetExecuteCommandSecondary() );
105 		m_Result.SetViewCommand( GetViewCommand() );
106 		m_Result.SetViewCommandSecondary( GetViewCommandSecondary() );
107 		m_Result.SetEditCommand( GetEditCommand() );
108 		m_Result.SetEditCommandSecondary( GetEditCommandSecondary() );
109 		m_Result.SetHasTerminal( m_HasTerminalButton.IsSet() );
110 
111 		return m_Result;
112 	}
113 
114 private:
115 	Layout m_Layout;
116 
117 public:
118 	StaticLabel m_MaskText;
119 	EditLine   m_MaskEdit;
120 
121 	StaticLabel m_DescriptionText;
122 	EditLine   m_DescriptionEdit;
123 
124 	SButton m_HasTerminalButton;
125 
126 	StaticLabel m_ExecuteCommandText;
127 	EditLine   m_ExecuteCommandEdit;
128 
129 	StaticLabel m_ExecuteCommandSecondaryText;
130 	EditLine   m_ExecuteCommandSecondaryEdit;
131 
132 	StaticLabel m_ViewCommandText;
133 	EditLine   m_ViewCommandEdit;
134 
135 	StaticLabel m_ViewCommandSecondaryText;
136 	EditLine   m_ViewCommandSecondaryEdit;
137 
138 	StaticLabel m_EditCommandText;
139 	EditLine   m_EditCommandEdit;
140 
141 	StaticLabel m_EditCommandSecondaryText;
142 	EditLine   m_EditCommandSecondaryEdit;
143 
144 	mutable clNCFileAssociation m_Result;
145 
146 	bool m_Saved;
147 };
148 
149 class clFileAssociationsListWin: public iContainerListWin<clNCFileAssociation>
150 {
151 public:
clFileAssociationsListWin(Win * Parent,std::vector<clNCFileAssociation> * Associations)152 	clFileAssociationsListWin( Win* Parent, std::vector<clNCFileAssociation>* Associations )
153 		: iContainerListWin<clNCFileAssociation>( Parent, Associations )
154 	{
155 	}
156 
157 	virtual void DrawItem( wal::GC& gc, int n, crect rect ) override;
158 };
159 
160 static int uiFcColor = GetUiID( "first-char-color" );
161 
DrawItem(wal::GC & gc,int n,crect rect)162 void clFileAssociationsListWin::DrawItem( wal::GC& gc, int n, crect rect )
163 {
164 	if ( n < 0 || n >= ( int )m_ItemList->size( ) )
165 	{
166 		gc.SetFillColor( UiGetColor( uiBackground, 0, 0, 0xB0B000 ) );
167 		gc.FillRect( rect ); //CCC
168 		return;
169 	}
170 
171 	UiCondList ucl;
172 
173 	if ( ( n % 2 ) == 0 ) { ucl.Set( uiOdd, true ); }
174 
175 	if ( n == this->GetCurrent() ) { ucl.Set( uiCurrentItem, true ); }
176 
177 	unsigned bg = UiGetColor( uiBackground, uiItem, &ucl, 0xB0B000 );
178 	unsigned color = UiGetColor( uiColor, uiItem, &ucl, 0 );
179 	unsigned fcColor = UiGetColor( uiFcColor, uiItem, &ucl, 0xFFFF );
180 
181 	gc.SetFillColor( bg );
182 	gc.FillRect( rect );
183 
184 	const clNCFileAssociation* p = &m_ItemList->at( n );
185 
186 	if ( p )
187 	{
188 		gc.Set( GetFont() );
189 		gc.SetTextColor( color );
190 		gc.TextOutF( rect.left + 10, rect.top + 1, p->GetMask().data() );
191 		gc.SetTextColor( fcColor );
192 		gc.TextOutF( rect.left + 10, rect.top + 1, p->GetMask().data(), 1 );
193 	}
194 }
195 
196 class clFileAssociationsWin: public NCDialog
197 {
198 	clFileAssociationsListWin m_ListWin;
199 	Layout m_Layout;
200 	Button m_AddCurrentButton;
201 	Button m_DelButton;
202 	Button m_EditButton;
203 	bool   m_Saved;
204 public:
clFileAssociationsWin(NCDialogParent * parent,std::vector<clNCFileAssociation> * Associations)205 	clFileAssociationsWin( NCDialogParent* parent, std::vector<clNCFileAssociation>* Associations )
206 		: NCDialog( ::createDialogAsChild, 0, parent, utf8_to_unicode( _LT( "File associations" ) ).data(), bListOkCancel )
207 		, m_ListWin( this, Associations )
208 		, m_Layout( 10, 10 )
209 		, m_AddCurrentButton( 0, this, utf8_to_unicode( "+ (&Ins)" ).data(), CMD_PLUS )
210 		, m_DelButton( 0, this, utf8_to_unicode( "- (&Del)" ).data(), CMD_MINUS )
211 		, m_EditButton( 0, this, utf8_to_unicode( _LT( "&Edit" ) ).data(), CMD_EDIT )
212 		, m_Saved( true )
213 	{
214 		m_AddCurrentButton.Enable();
215 		m_AddCurrentButton.Show();
216 		m_DelButton.Enable();
217 		m_DelButton.Show();
218 		m_EditButton.Enable();
219 		m_EditButton.Show();
220 
221 		LSize lsize = m_AddCurrentButton.GetLSize();
222 		LSize lsize2 = m_DelButton.GetLSize();
223 		LSize lsize3 = m_EditButton.GetLSize();
224 
225 		if ( lsize.x.minimal < lsize2.x.minimal ) { lsize.x.minimal = lsize2.x.minimal; }
226 
227 		if ( lsize.x.minimal < lsize3.x.minimal ) { lsize.x.minimal = lsize3.x.minimal; }
228 
229 		if ( lsize.x.maximal < lsize.x.minimal ) { lsize.x.maximal = lsize.x.minimal; }
230 
231 		m_AddCurrentButton.SetLSize( lsize );
232 		m_DelButton.SetLSize( lsize );
233 		m_EditButton.SetLSize( lsize );
234 
235 		m_Layout.AddWinAndEnable( &m_ListWin, 0, 0, 9, 0 );
236 		m_Layout.AddWin( &m_AddCurrentButton, 0, 1 );
237 		m_Layout.AddWin( &m_DelButton, 1, 1 );
238 		m_Layout.AddWin( &m_EditButton, 2, 1 );
239 		m_Layout.SetLineGrowth( 9 );
240 
241 		this->AddLayout( &m_Layout );
242 
243 		SetPosition();
244 
245 		m_ListWin.SetFocus();
246 		this->SetEnterCmd( CMD_OK );
247 	}
248 
249 	virtual bool Command( int id, int subId, Win* win, void* data );
250 	virtual int UiGetClassId();
251 	virtual bool EventChildKey( Win* child, cevent_key* pEvent );
252 	virtual bool EventKey( cevent_key* pEvent );
253 
254 	bool Key( cevent_key* pEvent );
255 
256 	virtual ~clFileAssociationsWin();
257 };
258 
259 int uiClassFileAssociations = GetUiID( "Shortcuts" );
260 
UiGetClassId()261 int clFileAssociationsWin::UiGetClassId() { return uiClassFileAssociations; }
262 
Command(int id,int subId,Win * win,void * data)263 bool clFileAssociationsWin::Command( int id, int subId, Win* win, void* data )
264 {
265 	if ( id == CMD_OK )
266 	{
267 		EndModal( CMD_OK );
268 		return true;
269 	}
270 
271 	if ( id == CMD_MINUS )
272 	{
273 		const clNCFileAssociation* p = m_ListWin.GetCurrentData();
274 
275 		if ( !p ) { return true; }
276 
277 		if ( NCMessageBox( ( NCDialogParent* )Parent(), _LT( "Delete item" ),
278 		                   carray_cat<char>( _LT( "Delete '" ), unicode_to_utf8( p->GetMask().data() ).data() , "' ?" ).data(),
279 		                   false, bListOkCancel ) == CMD_OK )
280 		{
281 			m_ListWin.Del();
282 			m_Saved = false;
283 		}
284 
285 		return true;
286 	}
287 
288 	if ( id == CMD_EDIT || ( id == CMD_ITEM_CLICK && win == &m_ListWin ) )
289 	{
290 		const clNCFileAssociation* ValueToEdit = m_ListWin.GetCurrentData();
291 
292 		if ( !ValueToEdit ) { return true; }
293 
294 		clEditFileAssociationsWin Dialog( ( NCDialogParent* )Parent(), ValueToEdit );
295 		Dialog.SetEnterCmd( 0 );
296 
297 		if ( Dialog.DoModal( ) == CMD_OK )
298 		{
299 			m_ListWin.Rename( Dialog.GetResult( ) );
300 			m_Saved = false;
301 		}
302 
303 		return true;
304 	}
305 
306 	if ( id == CMD_PLUS )
307 	{
308 		clEditFileAssociationsWin Dialog( ( NCDialogParent* )Parent(), NULL );
309 		Dialog.SetEnterCmd( 0 );
310 
311 		if ( Dialog.DoModal( ) == CMD_OK )
312 		{
313 			m_ListWin.Ins( Dialog.GetResult( ) );
314 			m_Saved = false;
315 		}
316 
317 		return true;
318 	}
319 
320 	return NCDialog::Command( id, subId, win, data );
321 }
322 
Key(cevent_key * pEvent)323 bool clFileAssociationsWin::Key( cevent_key* pEvent )
324 {
325 	if ( pEvent->Type() == EV_KEYDOWN )
326 	{
327 		if ( pEvent->Key() == VK_ESCAPE )
328 		{
329 			if ( m_Saved || NCMessageBox( ( NCDialogParent* )Parent(), _LT( "Warning" ), _LT( "Quit without saving?" ), true, bListOkCancel ) == CMD_OK )
330 			{
331 				return false;
332 			}
333 
334 			return true;
335 		}
336 
337 		if ( pEvent->Key() == VK_INSERT )
338 		{
339 			Command( CMD_PLUS, 0, this, 0 );
340 			return true;
341 		}
342 
343 		if ( pEvent->Key() == VK_DELETE )
344 		{
345 			Command( CMD_MINUS, 0, this, 0 );
346 			return true;
347 		}
348 
349 		if ( pEvent->Key() == VK_F4 )
350 		{
351 			Command( CMD_EDIT, 0, this, 0 );
352 			return true;
353 		}
354 
355 		if ( pEvent->Key() == VK_RETURN && m_ListWin.InFocus() )
356 		{
357 			Command( CMD_EDIT, 0, this, 0 );
358 			return true;
359 		}
360 
361 //		unicode_t c = UnicodeLC( pEvent->Char() );
362 	}
363 
364 	return false;
365 }
366 
EventChildKey(Win * child,cevent_key * pEvent)367 bool clFileAssociationsWin::EventChildKey( Win* child, cevent_key* pEvent )
368 {
369 	if ( Key( pEvent ) ) { return true; }
370 
371 	return NCDialog::EventChildKey( child, pEvent );
372 }
373 
EventKey(cevent_key * pEvent)374 bool clFileAssociationsWin::EventKey( cevent_key* pEvent )
375 {
376 	if ( Key( pEvent ) ) { return true; }
377 
378 	return NCDialog::EventKey( pEvent );
379 }
380 
~clFileAssociationsWin()381 clFileAssociationsWin::~clFileAssociationsWin()
382 {
383 }
384 
FileAssociationsDlg(NCDialogParent * Parent,std::vector<clNCFileAssociation> * Associations)385 bool FileAssociationsDlg( NCDialogParent* Parent, std::vector<clNCFileAssociation>* Associations )
386 {
387 	// make an editable copy
388 	std::vector<clNCFileAssociation> LocalAssociations( *Associations );
389 
390 	clFileAssociationsWin Dialog( Parent, &LocalAssociations );
391 	Dialog.SetEnterCmd( 0 );
392 
393 	if ( Dialog.DoModal( ) == CMD_OK )
394 	{
395 		// apply changes
396 		*Associations = LocalAssociations;
397 
398 		return true;
399 	}
400 
401 	return false;
402 }
403