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