~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/EditorTweaks/EditorTweaks.cpp

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <sdk.h> // Code::Blocks SDK
 
2
#include <algorithm> // std::sort
 
3
#include <configurationpanel.h>
 
4
#include "EditorTweaks.h"
 
5
 
 
6
#ifndef CB_PRECOMP
 
7
    #include <wx/menu.h>
 
8
    #include <wx/textdlg.h>
 
9
    #include <wx/toolbar.h>
 
10
#endif
 
11
 
 
12
#include "EditorTweaksConfDlg.h"
 
13
 
 
14
 
 
15
#include <manager.h>
 
16
#include <configmanager.h>
 
17
#include <logmanager.h>
 
18
#include <editor_hooks.h>
 
19
#include <cbeditor.h>
 
20
#include <wx/wxscintilla.h>
 
21
#include <editormanager.h>
 
22
#include "cbstyledtextctrl.h"
 
23
 
 
24
 
 
25
// Register the plugin with Code::Blocks.
 
26
// We are using an anonymous namespace so we don't litter the global one.
 
27
namespace
 
28
{
 
29
    PluginRegistrant<EditorTweaks> reg(_T("EditorTweaks"));
 
30
 
 
31
    struct CompareAlignerMenuEntry
 
32
    {
 
33
        bool operator() (AlignerMenuEntry i, AlignerMenuEntry j) { return (i.UsageCount<=j.UsageCount);}
 
34
    } CompareAlignerMenuEntryObject;
 
35
 
 
36
    const unsigned int defaultStoredAlignerEntries = 4;
 
37
 
 
38
    wxString defaultNames[defaultStoredAlignerEntries] = { _T("Equality Operator"), _T("C/C++ line Comment "), _T("VHDL Signal Assignment"), _T("VHDL named association")};
 
39
    wxString defaultStrings[defaultStoredAlignerEntries] = { _T("="), _T("//"), _T("<="), _T("=>") };
 
40
 
 
41
}
 
42
 
 
43
int id_et                     = wxNewId();
 
44
int id_et_WordWrap            = wxNewId();
 
45
int id_et_CharWrap            = wxNewId();
 
46
int id_et_ShowLineNumbers     = wxNewId();
 
47
int id_et_TabChar             = wxNewId();
 
48
int id_et_TabIndent           = wxNewId();
 
49
int id_et_TabSize2            = wxNewId();
 
50
int id_et_TabSize4            = wxNewId();
 
51
int id_et_TabSize6            = wxNewId();
 
52
int id_et_TabSize8            = wxNewId();
 
53
int id_et_ConsistentIndent    = wxNewId();
 
54
int id_et_ShowWhitespaceChars = wxNewId();
 
55
int id_et_ShowEOL             = wxNewId();
 
56
int id_et_StripTrailingBlanks = wxNewId();
 
57
int id_et_EnsureConsistentEOL = wxNewId();
 
58
int id_et_EOLCRLF             = wxNewId();
 
59
int id_et_EOLCR               = wxNewId();
 
60
int id_et_EOLLF               = wxNewId();
 
61
int id_et_Fold1               = wxNewId();
 
62
int id_et_Fold2               = wxNewId();
 
63
int id_et_Fold3               = wxNewId();
 
64
int id_et_Fold4               = wxNewId();
 
65
int id_et_Fold5               = wxNewId();
 
66
int id_et_Unfold1             = wxNewId();
 
67
int id_et_Unfold2             = wxNewId();
 
68
int id_et_Unfold3             = wxNewId();
 
69
int id_et_Unfold4             = wxNewId();
 
70
int id_et_Unfold5             = wxNewId();
 
71
int id_et_align_others        = wxNewId();
 
72
int id_et_align_auto          = wxNewId();
 
73
int id_et_align_last          = wxNewId();
 
74
int id_et_LaptopFriendly      = wxNewId();
 
75
int id_et_SuppressInsertKey   = wxNewId();
 
76
int id_et_ConvertBraces       = wxNewId();
 
77
int id_et_ScrollTimer         = wxNewId();
 
78
 
 
79
// events handling
 
80
BEGIN_EVENT_TABLE(EditorTweaks, cbPlugin)
 
81
    EVT_UPDATE_UI(id_et_WordWrap, EditorTweaks::OnUpdateUI)
 
82
    EVT_UPDATE_UI(id_et_CharWrap, EditorTweaks::OnUpdateUI)
 
83
    EVT_UPDATE_UI(id_et_ShowLineNumbers, EditorTweaks::OnUpdateUI)
 
84
    EVT_UPDATE_UI(id_et_TabChar, EditorTweaks::OnUpdateUI)
 
85
    EVT_UPDATE_UI(id_et_TabIndent, EditorTweaks::OnUpdateUI)
 
86
    EVT_UPDATE_UI(id_et_TabSize2, EditorTweaks::OnUpdateUI)
 
87
    EVT_UPDATE_UI(id_et_TabSize4, EditorTweaks::OnUpdateUI)
 
88
    EVT_UPDATE_UI(id_et_TabSize6, EditorTweaks::OnUpdateUI)
 
89
    EVT_UPDATE_UI(id_et_TabSize8, EditorTweaks::OnUpdateUI)
 
90
    EVT_UPDATE_UI(id_et_ShowEOL, EditorTweaks::OnUpdateUI)
 
91
    EVT_UPDATE_UI(id_et_StripTrailingBlanks, EditorTweaks::OnUpdateUI)
 
92
    EVT_UPDATE_UI(id_et_EnsureConsistentEOL, EditorTweaks::OnUpdateUI)
 
93
    EVT_UPDATE_UI(id_et_EOLCRLF, EditorTweaks::OnUpdateUI)
 
94
    EVT_UPDATE_UI(id_et_EOLCR, EditorTweaks::OnUpdateUI)
 
95
    EVT_UPDATE_UI(id_et_EOLLF, EditorTweaks::OnUpdateUI)
 
96
 
 
97
 
 
98
    EVT_MENU(id_et_WordWrap, EditorTweaks::OnWordWrap)
 
99
    EVT_MENU(id_et_CharWrap, EditorTweaks::OnCharWrap)
 
100
    EVT_MENU(id_et_ShowLineNumbers, EditorTweaks::OnShowLineNumbers)
 
101
    EVT_MENU(id_et_TabChar, EditorTweaks::OnTabChar)
 
102
    EVT_MENU(id_et_TabIndent, EditorTweaks::OnTabIndent)
 
103
    EVT_MENU(id_et_TabSize2, EditorTweaks::OnTabSize2)
 
104
    EVT_MENU(id_et_TabSize4, EditorTweaks::OnTabSize4)
 
105
    EVT_MENU(id_et_TabSize6, EditorTweaks::OnTabSize6)
 
106
    EVT_MENU(id_et_TabSize8, EditorTweaks::OnTabSize8)
 
107
    EVT_MENU(id_et_ConsistentIndent, EditorTweaks::OnMakeIndentsConsistent)
 
108
    EVT_MENU(id_et_ShowWhitespaceChars, EditorTweaks::OnShowWhitespaceChars)
 
109
    EVT_MENU(id_et_ShowEOL, EditorTweaks::OnShowEOL)
 
110
    EVT_MENU(id_et_StripTrailingBlanks, EditorTweaks::OnStripTrailingBlanks)
 
111
    EVT_MENU(id_et_EnsureConsistentEOL, EditorTweaks::OnEnsureConsistentEOL)
 
112
    EVT_MENU(id_et_EOLCRLF, EditorTweaks::OnEOLCRLF)
 
113
    EVT_MENU(id_et_EOLCR, EditorTweaks::OnEOLCR)
 
114
    EVT_MENU(id_et_EOLLF, EditorTweaks::OnEOLLF)
 
115
    EVT_MENU(id_et_Fold1, EditorTweaks::OnFold)
 
116
    EVT_MENU(id_et_Fold2, EditorTweaks::OnFold)
 
117
    EVT_MENU(id_et_Fold3, EditorTweaks::OnFold)
 
118
    EVT_MENU(id_et_Fold4, EditorTweaks::OnFold)
 
119
    EVT_MENU(id_et_Fold5, EditorTweaks::OnFold)
 
120
    EVT_MENU(id_et_Unfold1, EditorTweaks::OnUnfold)
 
121
    EVT_MENU(id_et_Unfold2, EditorTweaks::OnUnfold)
 
122
    EVT_MENU(id_et_Unfold3, EditorTweaks::OnUnfold)
 
123
    EVT_MENU(id_et_Unfold4, EditorTweaks::OnUnfold)
 
124
    EVT_MENU(id_et_Unfold5, EditorTweaks::OnUnfold)
 
125
 
 
126
    EVT_MENU(id_et_LaptopFriendly,     EditorTweaks::OnLaptopFriendly)
 
127
    EVT_MENU(id_et_SuppressInsertKey,  EditorTweaks::OnSuppressInsert)
 
128
    EVT_MENU(id_et_ConvertBraces,      EditorTweaks::OnConvertBraces)
 
129
    EVT_MENU(id_et_align_others,       EditorTweaks::OnAlignOthers)
 
130
    EVT_MENU(id_et_align_auto,         EditorTweaks::OnAlignAuto)
 
131
    EVT_MENU(id_et_align_last,         EditorTweaks::OnAlignLast)
 
132
 
 
133
    EVT_TIMER(id_et_ScrollTimer, EditorTweaks::OnScrollTimer)
 
134
END_EVENT_TABLE()
 
135
 
 
136
// constructor
 
137
EditorTweaks::EditorTweaks() :
 
138
    AlignerLastUsedIdx(0),
 
139
    AlignerLastUsedAuto(false),
 
140
    AlignerLastUsed(false),
 
141
    m_scrollTimer(this, id_et_ScrollTimer)
 
142
{
 
143
    // Make sure our resources are available.
 
144
    // In the generated boilerplate code we have no resources but when
 
145
    // we add some, it will be nice that this code is in place already ;)
 
146
    if (!Manager::LoadResource(_T("EditorTweaks.zip")))
 
147
        NotifyMissingFile(_T("EditorTweaks.zip"));
 
148
}
 
149
 
 
150
// destructor
 
151
EditorTweaks::~EditorTweaks()
 
152
{
 
153
}
 
154
 
 
155
void EditorTweaks::OnAttach()
 
156
{
 
157
    // do whatever initialization you need for your plugin
 
158
    // NOTE: after this function, the inherited member variable
 
159
    // m_IsAttached will be TRUE...
 
160
    // You should check for it in other functions, because if it
 
161
    // is FALSE, it means that the application did *not* "load"
 
162
    // (see: does not need) this plugin...
 
163
 
 
164
    Manager* pm = Manager::Get();
 
165
    pm->RegisterEventSink(cbEVT_EDITOR_OPEN, new cbEventFunctor<EditorTweaks, CodeBlocksEvent>(this, &EditorTweaks::OnEditorOpen));
 
166
 
 
167
    m_tweakmenu=NULL;
 
168
 
 
169
    EditorManager* em = Manager::Get()->GetEditorManager();
 
170
    for (int i=0;i<em->GetEditorsCount();i++)
 
171
    {
 
172
        cbEditor* ed=em->GetBuiltinEditor(i);
 
173
        if (ed && ed->GetControl())
 
174
        {
 
175
            ed->GetControl()->SetOvertype(false);
 
176
            ed->GetControl()->Connect(wxEVT_KEY_DOWN,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnKeyPress,NULL,this);
 
177
            ed->GetControl()->Connect(wxEVT_CHAR,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnChar,NULL,this);
 
178
        }
 
179
    }
 
180
 
 
181
 
 
182
    AlignerMenuEntry e;
 
183
 
 
184
    ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("EditorTweaks"));
 
185
 
 
186
    for (int i = 0 ; i < cfg->ReadInt(_T("/aligner/saved_entries"),defaultStoredAlignerEntries) ; ++i)
 
187
    {
 
188
        e.MenuName = cfg->Read(wxString::Format(_T("/aligner/first_name_%d"),i),defaultNames[i]);
 
189
        e.ArgumentString = cfg->Read(wxString::Format(_T("/aligner/first_argument_string_%d"),i) ,defaultStrings[i]);
 
190
        e.UsageCount = 0;
 
191
        e.id = wxNewId();
 
192
        AlignerMenuEntries.push_back(e);
 
193
        Connect(e.id, wxEVT_COMMAND_MENU_SELECTED,  wxCommandEventHandler(EditorTweaks::OnAlign) );
 
194
    }
 
195
    m_suppress_insert = cfg->ReadBool(wxT("/suppress_insert_key"), false);
 
196
    m_laptop_friendly = cfg->ReadBool(wxT("/laptop_friendly"),     false);
 
197
    m_convert_braces  = cfg->ReadBool(wxT("/convert_braces"),      false);
 
198
    m_buffer_caret    = -1;
 
199
}
 
200
 
 
201
void EditorTweaks::OnRelease(bool /*appShutDown*/)
 
202
{
 
203
    m_tweakmenu = 0;
 
204
 
 
205
//    EditorHooks::UnregisterHook(m_EditorHookId, true);
 
206
    EditorManager* em = Manager::Get()->GetEditorManager();
 
207
    for (int i=0;i<em->GetEditorsCount();i++)
 
208
    {
 
209
        cbEditor* ed=em->GetBuiltinEditor(i);
 
210
        if (ed && ed->GetControl())
 
211
        {
 
212
            ed->GetControl()->Disconnect(wxEVT_NULL,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnKeyPress);
 
213
            ed->GetControl()->Disconnect(wxEVT_NULL,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnChar);
 
214
        }
 
215
    }
 
216
 
 
217
    AlignerMenuEntry e;
 
218
 
 
219
    ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("EditorTweaks"));
 
220
    std::sort (AlignerMenuEntries.begin(), AlignerMenuEntries.end(),CompareAlignerMenuEntryObject);
 
221
    std::reverse( AlignerMenuEntries.begin(), AlignerMenuEntries.end());
 
222
    int i = 0;
 
223
    for (; i < cfg->ReadInt(_T("/aligner/max_saved_entries"),defaultStoredAlignerEntries) && i < static_cast<int>(AlignerMenuEntries.size()) ; ++i)
 
224
    {
 
225
        cfg->Write(wxString::Format(_T("/aligner/first_name_%d"),i),AlignerMenuEntries[i].MenuName);
 
226
        cfg->Write(wxString::Format(_T("/aligner/first_argument_string_%d"),i) ,AlignerMenuEntries[i].ArgumentString);
 
227
 
 
228
        Disconnect(AlignerMenuEntries[i].id, wxEVT_COMMAND_MENU_SELECTED,  wxCommandEventHandler(EditorTweaks::OnAlign) );
 
229
    }
 
230
    cfg->Write(_T("/aligner/saved_entries"),i);
 
231
    for (; i < static_cast<int>(AlignerMenuEntries.size()) ; ++i)
 
232
        Disconnect(AlignerMenuEntries[i].id, wxEVT_COMMAND_MENU_SELECTED,  wxCommandEventHandler(EditorTweaks::OnAlign) );
 
233
    cfg->Write(wxT("/suppress_insert_key"), m_suppress_insert);
 
234
    cfg->Write(wxT("/laptop_friendly"),     m_laptop_friendly);
 
235
    cfg->Write(wxT("/convert_braces"),      m_convert_braces);
 
236
}
 
237
 
 
238
cbConfigurationPanel* EditorTweaks::GetConfigurationPanel(wxWindow* parent)
 
239
{
 
240
    if ( !IsAttached() )
 
241
        return NULL;
 
242
 
 
243
    m_buffer_caret = -1; // invalidate so value will be read from configuration on next use
 
244
    EditorTweaksConfDlg* cfg = new EditorTweaksConfDlg(parent);
 
245
    return cfg;
 
246
}
 
247
 
 
248
void EditorTweaks::BuildMenu(wxMenuBar* menuBar)
 
249
{
 
250
    Manager::Get()->GetLogManager()->DebugLog(_("Editor Tweaks plugin: Building menu"));
 
251
    int i=menuBar->FindMenu(_("&Edit"));
 
252
    if (i==wxNOT_FOUND)
 
253
    {
 
254
        Manager::Get()->GetLogManager()->DebugLog(_("Editor Tweaks plugin: edit menu not found"));
 
255
        return;
 
256
    }
 
257
    wxMenu *menu=menuBar->GetMenu(i);
 
258
    for (i = 0; i < static_cast<int>(menu->GetMenuItemCount()); ++i)
 
259
    {
 
260
        wxMenuItem *mm=menu->FindItemByPosition(i);
 
261
        #if wxCHECK_VERSION(2, 9, 0)
 
262
        if (mm->GetItemLabel()==_("End-of-line mode"))
 
263
        #else
 
264
        if (mm->GetLabel()==_("End-of-line mode"))
 
265
        #endif
 
266
            menu->Remove(mm);
 
267
        #if wxCHECK_VERSION(2, 9, 0)
 
268
        if (mm->GetItemLabel()==_("Special commands"))
 
269
        #else
 
270
        if (mm->GetLabel()==_("Special commands"))
 
271
        #endif
 
272
            break;
 
273
    }
 
274
    if (i == static_cast<int>(menu->GetMenuItemCount()))
 
275
    {
 
276
        Manager::Get()->GetLogManager()->DebugLog(_("Editor Tweaks plugin: Special commands menu not found"));
 
277
        return;
 
278
    }
 
279
    Manager::Get()->GetLogManager()->DebugLog(wxString::Format(_("Editor Tweaks plugin: making the menu %i"),i));
 
280
    m_tweakmenu=new wxMenu();
 
281
    m_tweakmenuitem=new wxMenuItem(menu, id_et, _("Editor Tweaks"), _("Tweak the settings of the active editor"), wxITEM_NORMAL, m_tweakmenu);
 
282
    menu->Insert(i+1,m_tweakmenuitem);
 
283
 
 
284
    wxMenu *submenu=m_tweakmenu; //_("Editor Tweaks")
 
285
 
 
286
    submenu->AppendCheckItem( id_et_WordWrap, _( "Word wrap" ), _( "Wrap word" ) );
 
287
    submenu->AppendCheckItem( id_et_CharWrap, _( "Char wrap" ), _( "Wrap char" ) );
 
288
    submenu->AppendCheckItem( id_et_ShowLineNumbers, _( "Show Line Numbers" ), _( "Show Line Numbers" ) );
 
289
    submenu->AppendSeparator();
 
290
    submenu->AppendCheckItem( id_et_TabChar, _( "Use Tab Character" ), _( "Use Tab Character" ) );
 
291
    submenu->AppendCheckItem( id_et_TabIndent, _( "Tab Indents" ), _( "Tab Indents" ) );
 
292
    wxMenu *tabsizemenu=new wxMenu();
 
293
    tabsizemenu->AppendRadioItem( id_et_TabSize2, _( "2" ), _( "Tab Width of 2" ) );
 
294
    tabsizemenu->AppendRadioItem( id_et_TabSize4, _( "4" ), _( "Tab Width of 4" ) );
 
295
    tabsizemenu->AppendRadioItem( id_et_TabSize6, _( "6" ), _( "Tab Width of 6" ) );
 
296
    tabsizemenu->AppendRadioItem( id_et_TabSize8, _( "8" ), _( "Tab Width of 8" ) );
 
297
    submenu->Append(wxID_ANY,_("Tab Size"),tabsizemenu);
 
298
    submenu->Append( id_et_ConsistentIndent, _( "Make Indents Consistent" ),  _( "Convert leading tabs/spaces to the active setting" ) );
 
299
    submenu->AppendCheckItem(id_et_ShowWhitespaceChars, _("Show whitespace characters"),
 
300
                             _("Shows the space and tab characters in the editor"));
 
301
    submenu->AppendSeparator();
 
302
    wxMenu *eolmenu=new wxMenu();
 
303
    eolmenu->AppendRadioItem( id_et_EOLCRLF, _( "CR LF" ), _( "Carriage Return - Line Feed (Windows Default)" ) );
 
304
    eolmenu->AppendRadioItem( id_et_EOLCR,   _( "CR" ),    _( "Carriage Return (Mac Default)" ) );
 
305
    eolmenu->AppendRadioItem( id_et_EOLLF,   _( "LF" ),    _( "Line Feed (Unix Default)" ) );
 
306
    submenu->Append(wxID_ANY,_("End-of-Line Mode"),eolmenu);
 
307
    submenu->AppendCheckItem( id_et_ShowEOL,    _( "Show EOL Chars" ),            _( "Show End-of-Line Characters" ) );
 
308
    submenu->Append( id_et_StripTrailingBlanks, _( "Strip Trailing Blanks Now" ), _( "Strip trailing blanks from each line" ) );
 
309
    submenu->Append( id_et_EnsureConsistentEOL, _( "Make EOLs Consistent Now" ),  _( "Convert End-of-Line Characters to the Active Setting" ) );
 
310
    submenu->AppendSeparator();
 
311
    submenu->AppendCheckItem( id_et_LaptopFriendly,    _("Laptop Friendly Keyboard Navigation"),   _("Enables keyboard shortcuts: Shift+Backspace = Delete, Alt+Down = Page Down, Alt+Up = Page Up, Alt+Left = Home, Alt+Right = End") );
 
312
    submenu->AppendCheckItem( id_et_SuppressInsertKey, _("Suppress Insert Key"),                   _("Disable the effect of the insert key (toggle between insert and overwrite mode)") );
 
313
    submenu->AppendCheckItem( id_et_ConvertBraces,     _("Convert Matching Braces"),               _("Selecting a brace and typing a new brace character will change the matching brace appropriately") );
 
314
    submenu->AppendSeparator();
 
315
    submenu->Append( id_et_align_last,        _("Last Align"), _("repeat last Align command") );
 
316
    submenu->Append( id_et_align_auto,        _("Auto Align"), _("Align lines automatically") );
 
317
 
 
318
 
 
319
    wxMenu *foldmenu = 0;
 
320
    for (i = 0; i < static_cast<int>(menu->GetMenuItemCount()); ++i)
 
321
    {
 
322
        wxMenuItem *mm = menu->FindItemByPosition(i);
 
323
        #if wxCHECK_VERSION(2, 9, 0)
 
324
        if (mm->GetItemLabel()==_("Folding"))
 
325
        #else
 
326
        if (mm->GetLabel()==_("Folding"))
 
327
        #endif
 
328
        {
 
329
            foldmenu=mm->GetSubMenu();
 
330
            break;
 
331
        }
 
332
    }
 
333
    if (!foldmenu)
 
334
    {
 
335
        Manager::Get()->GetLogManager()->DebugLog(_("Editor Tweaks plugin: Folding menu"));
 
336
        return;
 
337
    }
 
338
 
 
339
    foldmenu->AppendSeparator();
 
340
    wxMenu *foldlevelmenu=new wxMenu();
 
341
    foldlevelmenu->Append( id_et_Fold1, _( "1" ), _( "Fold all code to the first level" ) );
 
342
    foldlevelmenu->Append( id_et_Fold2, _( "2" ), _( "Fold all code to the second level" ) );
 
343
    foldlevelmenu->Append( id_et_Fold3, _( "3" ), _( "Fold all code to the third level" ) );
 
344
    foldlevelmenu->Append( id_et_Fold4, _( "4" ), _( "Fold all code to the fourth level" ) );
 
345
    foldlevelmenu->Append( id_et_Fold5, _( "5" ), _( "Fold all code to the fifth level" ) );
 
346
    foldmenu->Append(wxID_ANY,_("Fold all above level"),foldlevelmenu);
 
347
 
 
348
    wxMenu *unfoldlevelmenu=new wxMenu();
 
349
    unfoldlevelmenu->Append( id_et_Unfold1, _( "1" ), _( "Unfold all code to the first level" ) );
 
350
    unfoldlevelmenu->Append( id_et_Unfold2, _( "2" ), _( "Unfold all code to the second level" ) );
 
351
    unfoldlevelmenu->Append( id_et_Unfold3, _( "3" ), _( "Unfold all code to the third level" ) );
 
352
    unfoldlevelmenu->Append( id_et_Unfold4, _( "4" ), _( "Unfold all code to the fourth level" ) );
 
353
    unfoldlevelmenu->Append( id_et_Unfold5, _( "5" ), _( "Unfold all code to the fifth level" ) );
 
354
    foldmenu->Append(wxID_ANY,_("Unfold all above level"),unfoldlevelmenu);
 
355
 
 
356
    UpdateUI();
 
357
}
 
358
 
 
359
 
 
360
void EditorTweaks::UpdateUI()
 
361
{
 
362
    if (!m_tweakmenu)
 
363
        return;
 
364
 
 
365
    cbStyledTextCtrl* control = GetSafeControl();
 
366
    if (!control)
 
367
        m_tweakmenuitem->Enable(false);
 
368
    else
 
369
        m_tweakmenuitem->Enable(true);
 
370
 
 
371
    wxMenu *submenu = m_tweakmenu;
 
372
 
 
373
    if(control)
 
374
    {
 
375
        submenu->Check(id_et_WordWrap,control->GetWrapMode()==wxSCI_WRAP_WORD);
 
376
        submenu->Check(id_et_CharWrap,control->GetWrapMode()==wxSCI_WRAP_CHAR);
 
377
        submenu->Check(id_et_ShowLineNumbers,control->GetMarginWidth(0)>0);
 
378
        submenu->Check(id_et_TabChar,control->GetUseTabs());
 
379
        submenu->Check(id_et_TabIndent,control->GetTabIndents());
 
380
        submenu->Check(id_et_TabSize2,control->GetTabWidth()==2);
 
381
        submenu->Check(id_et_TabSize4,control->GetTabWidth()==4);
 
382
        submenu->Check(id_et_TabSize6,control->GetTabWidth()==6);
 
383
        submenu->Check(id_et_TabSize8,control->GetTabWidth()==8);
 
384
        submenu->Check(id_et_EOLCRLF,control->GetEOLMode()==wxSCI_EOL_CRLF);
 
385
        submenu->Check(id_et_EOLCR,control->GetEOLMode()==wxSCI_EOL_CR);
 
386
        submenu->Check(id_et_EOLLF,control->GetEOLMode()==wxSCI_EOL_LF);
 
387
        submenu->Check(id_et_ShowEOL,control->GetViewEOL());
 
388
        submenu->Check(id_et_ShowWhitespaceChars, control->GetViewWhiteSpace()!=wxSCI_WS_INVISIBLE);
 
389
    }
 
390
    submenu->Check(id_et_SuppressInsertKey, m_suppress_insert);
 
391
    submenu->Check(id_et_LaptopFriendly, m_laptop_friendly);
 
392
    submenu->Check(id_et_ConvertBraces,     m_convert_braces);
 
393
}
 
394
 
 
395
void EditorTweaks::OnUpdateUI(wxUpdateUIEvent &/*event*/)
 
396
{
 
397
    if ( !IsAttached() )
 
398
        return;
 
399
 
 
400
    UpdateUI();
 
401
}
 
402
 
 
403
void EditorTweaks::OnEditorOpen(CodeBlocksEvent& /*event*/)
 
404
{
 
405
    Manager::Get()->GetLogManager()->DebugLog(wxString::Format(_("Editor Open")));
 
406
    cbStyledTextCtrl* control = GetSafeControl();
 
407
    if (!control)
 
408
        return;
 
409
 
 
410
    control->SetOvertype(false);
 
411
    control->Connect(wxEVT_KEY_DOWN,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnKeyPress,NULL,this);
 
412
    control->Connect(wxEVT_CHAR,(wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction)&EditorTweaks::OnChar,NULL,this);
 
413
 
 
414
}
 
415
 
 
416
void EditorTweaks::OnKeyPress(wxKeyEvent& event)
 
417
{
 
418
    const int keyCode = event.GetKeyCode();
 
419
    switch (keyCode)
 
420
    {
 
421
    case WXK_NUMPAD_UP:      case WXK_UP:
 
422
        if (event.GetModifiers() != wxMOD_CONTROL)
 
423
            DoBufferEditorPos(-1);
 
424
        break;
 
425
 
 
426
    case WXK_NUMPAD_DOWN:    case WXK_DOWN:
 
427
        if (event.GetModifiers() == wxMOD_CONTROL)
 
428
            break;
 
429
        // fall through
 
430
    case WXK_NUMPAD_ENTER:   case WXK_RETURN:
 
431
        DoBufferEditorPos(1);
 
432
        break;
 
433
 
 
434
    case WXK_NUMPAD_TAB:     case WXK_TAB:
 
435
        if (event.GetModifiers() != wxMOD_NONE)
 
436
            break;
 
437
        // fall through
 
438
    case WXK_BACK:
 
439
    case WXK_NUMPAD_DELETE:  case WXK_DELETE:
 
440
    case WXK_NUMPAD_LEFT:    case WXK_LEFT:
 
441
    case WXK_NUMPAD_RIGHT:   case WXK_RIGHT:
 
442
        if (event.GetModifiers() == wxMOD_ALT)
 
443
            break;
 
444
        // fall through
 
445
    case WXK_NUMPAD_HOME:    case WXK_HOME:
 
446
    case WXK_NUMPAD_END:     case WXK_END:
 
447
        DoBufferEditorPos();
 
448
        break;
 
449
 
 
450
    default:
 
451
        break;
 
452
    }
 
453
    // This set of laptop friendly helpers are a bit of a hack to make up for the lack of
 
454
    // page up, page down, home, end, and delete keys on some laptops (especially Chromebooks)
 
455
    if (m_laptop_friendly && keyCode == WXK_LEFT && event.AltDown())
 
456
    {
 
457
        cbStyledTextCtrl* control = GetSafeControl();
 
458
        if (event.ShiftDown())
 
459
            control->VCHomeDisplayExtend();
 
460
        else
 
461
            control->VCHomeDisplay();
 
462
        event.Skip(false);
 
463
    }
 
464
    else if (m_laptop_friendly && keyCode == WXK_RIGHT && event.AltDown())
 
465
    {
 
466
        cbStyledTextCtrl* control = GetSafeControl();
 
467
        if (event.ShiftDown())
 
468
            control->LineEndDisplayExtend();
 
469
        else
 
470
            control->LineEndDisplay();
 
471
        event.Skip(false);
 
472
    }
 
473
    else if (m_laptop_friendly && keyCode == WXK_UP && event.AltDown())
 
474
    {
 
475
        cbStyledTextCtrl* control = GetSafeControl();
 
476
        if (event.ControlDown())
 
477
        {
 
478
            if (event.ShiftDown())
 
479
                control->DocumentStartExtend();
 
480
            else
 
481
                control->DocumentStart();
 
482
        } else
 
483
        {
 
484
            if (event.ShiftDown())
 
485
                control->PageUpExtend();
 
486
            else
 
487
                control->PageUp();
 
488
        }
 
489
        event.Skip(false);
 
490
    }
 
491
    else if (m_laptop_friendly && keyCode == WXK_DOWN && event.AltDown())
 
492
    {
 
493
        cbStyledTextCtrl* control = GetSafeControl();
 
494
        if (event.ControlDown())
 
495
        {
 
496
            if (event.ShiftDown())
 
497
                control->DocumentEndExtend();
 
498
            else
 
499
                control->DocumentEnd();
 
500
        } else
 
501
        {
 
502
            if (event.ShiftDown())
 
503
                control->PageDownExtend();
 
504
            else
 
505
                control->PageDown();
 
506
        }
 
507
        event.Skip(false);
 
508
    }
 
509
    else if (m_laptop_friendly && keyCode == WXK_BACK && event.GetModifiers() == wxMOD_SHIFT)
 
510
    {
 
511
        cbStyledTextCtrl* control = GetSafeControl();
 
512
        int anchor = control->GetAnchor();
 
513
        int pos = control->GetCurrentPos();
 
514
        if (anchor >= 0 && anchor != pos)
 
515
            control->DeleteRange(control->GetSelectionStart(), control->GetSelectionEnd() - control->GetSelectionStart());
 
516
        else
 
517
            control->DeleteRange(control->GetCurrentPos(), 1);
 
518
        event.Skip(false);
 
519
    }
 
520
    else if (m_suppress_insert && keyCode == WXK_INSERT && event.GetModifiers() == wxMOD_NONE)
 
521
        event.Skip(false);
 
522
    else if (m_convert_braces && keyCode == WXK_DELETE && (event.GetModifiers() == wxMOD_NONE || event.GetModifiers() == wxMOD_SHIFT))
 
523
    {
 
524
        event.Skip(true);
 
525
 
 
526
        cbStyledTextCtrl* control = GetSafeControl();
 
527
        if (!control)
 
528
            return;
 
529
 
 
530
        int p = control->GetCurrentPos();
 
531
        int a = control->GetAnchor();
 
532
        if (abs(p-a) != 1)
 
533
            return;
 
534
        int l = a<p? a: p;
 
535
        int m = control->BraceMatch(l);
 
536
        if (m == wxSCI_INVALID_POSITION)
 
537
            return;
 
538
        control->BeginUndoAction();
 
539
        if(l<m)
 
540
        {
 
541
            control->DeleteRange(m, 1);
 
542
            control->DeleteRange(l, 1);
 
543
        }
 
544
        else
 
545
        {
 
546
            control->DeleteRange(l, 1);
 
547
            control->DeleteRange(m, 1);
 
548
            l--;
 
549
        }
 
550
        control->SetCurrentPos(l);
 
551
        control->SetAnchor(l);
 
552
        control->EndUndoAction();
 
553
        event.Skip(false);
 
554
    }
 
555
    else
 
556
        event.Skip(true);
 
557
}
 
558
 
 
559
void EditorTweaks::OnChar(wxKeyEvent& event)
 
560
{
 
561
    event.Skip(true);
 
562
    DoBufferEditorPos();
 
563
    wxChar ch = event.GetKeyCode();
 
564
    if (m_convert_braces &&
 
565
            (ch == _T('(') ||
 
566
             ch == _T(')') ||
 
567
             ch == _T('[') ||
 
568
             ch == _T(']') ||
 
569
             ch == _T('<') ||
 
570
             ch == _T('>') ||
 
571
             ch == _T('{') ||
 
572
             ch == _T('}')
 
573
             ))
 
574
    {
 
575
        event.Skip(true);
 
576
 
 
577
        cbStyledTextCtrl* control = GetSafeControl();
 
578
        if (!control)
 
579
            return;
 
580
 
 
581
        int p = control->GetCurrentPos();
 
582
        int a = control->GetAnchor();
 
583
        if (abs(p-a) != 1)
 
584
            return;
 
585
        int l = a<p? a: p;
 
586
        wxString opch;
 
587
        switch (ch)
 
588
        {
 
589
            case _T('('):
 
590
                opch = _T(")");
 
591
                break;
 
592
            case _T(')'):
 
593
                opch = _T("(");
 
594
                break;
 
595
            case _T('['):
 
596
                opch = _T("]");
 
597
                break;
 
598
            case _T(']'):
 
599
                opch = _T("[");
 
600
                break;
 
601
            case _T('<'):
 
602
                opch = _T(">");
 
603
                break;
 
604
            case _T('>'):
 
605
                opch = _T("<");
 
606
                break;
 
607
            case _T('{'):
 
608
                opch = _T("}");
 
609
                break;
 
610
            case _T('}'):
 
611
                opch = _T("{");
 
612
                break;
 
613
            default:
 
614
              return;
 
615
        }
 
616
        int m = control->BraceMatch(l);
 
617
        if (m == wxSCI_INVALID_POSITION)
 
618
            return;
 
619
        control->BeginUndoAction();
 
620
        control->InsertText(l, wxString(ch,1));
 
621
        control->DeleteRange(l+1, 1);
 
622
        control->InsertText(m, opch);
 
623
        control->DeleteRange(m+1, 1);
 
624
        control->SetCurrentPos(p);
 
625
        control->SetAnchor(a);
 
626
        control->EndUndoAction();
 
627
        event.Skip(false);
 
628
    }
 
629
}
 
630
 
 
631
void EditorTweaks::OnSuppressInsert(wxCommandEvent& event)
 
632
{
 
633
    m_suppress_insert = event.IsChecked();
 
634
}
 
635
 
 
636
void EditorTweaks::OnLaptopFriendly(wxCommandEvent& event)
 
637
{
 
638
    m_laptop_friendly = event.IsChecked();
 
639
}
 
640
 
 
641
void EditorTweaks::OnConvertBraces(wxCommandEvent& event)
 
642
{
 
643
    m_convert_braces = event.IsChecked();
 
644
}
 
645
 
 
646
 
 
647
void EditorTweaks::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* /*data*/)
 
648
{
 
649
    //Some library module is ready to display a pop-up menu.
 
650
    //Check the parameter \"type\" and see which module it is
 
651
    //and append any items you need in the menu...
 
652
    //TIP: for consistency, add a separator as the first item...
 
653
 
 
654
    //make sure we have an editor
 
655
    if (type != mtEditorManager || !m_tweakmenu)
 
656
        return;
 
657
 
 
658
    cbStyledTextCtrl* control = GetSafeControl();
 
659
    if (!control)
 
660
    {
 
661
        m_tweakmenuitem->Enable(false);
 
662
        return;
 
663
    }
 
664
 
 
665
    m_tweakmenuitem->Enable(true);
 
666
 
 
667
    // build aligner menu and items
 
668
    wxMenu* alignerMenu = new wxMenu();
 
669
 
 
670
    std::sort (AlignerMenuEntries.begin(), AlignerMenuEntries.end(),CompareAlignerMenuEntryObject);
 
671
    std::reverse( AlignerMenuEntries.begin(), AlignerMenuEntries.end());
 
672
 
 
673
    for ( unsigned int i = 0; i < AlignerMenuEntries.size() ; i++ )
 
674
        alignerMenu->Append(AlignerMenuEntries[i].id, AlignerMenuEntries[i].MenuName + _T("\t")  + _T("[") + AlignerMenuEntries[i].ArgumentString + _T("]"));
 
675
    alignerMenu->AppendSeparator();
 
676
    alignerMenu->Append(id_et_align_auto,   _("Auto"));
 
677
    alignerMenu->Append(id_et_align_last,   _("Last Align"), _("repeat last Align command") );
 
678
    alignerMenu->Append(id_et_align_others, _("More ..."));
 
679
 
 
680
    // attach aligner menu
 
681
    menu->AppendSeparator();
 
682
    menu->Append(wxID_ANY, _T("Aligner"), alignerMenu);
 
683
 
 
684
    return;
 
685
 
 
686
// DISABLED ALL OF THE STUFF BELOW (IT IS ALREADY IN THE MAIN MENU BAR)
 
687
#if 0
 
688
    // build "editor tweaks" menu
 
689
    wxMenu *submenu=new wxMenu(); //_("Editor Tweaks")
 
690
 
 
691
    menu->Append(id_et,_("Editor Tweaks"),submenu);
 
692
 
 
693
    submenu->AppendCheckItem( id_et_WordWrap, _( "Word wrap" ), _( "Wrap word" ) );
 
694
    if (control->GetWrapMode()==wxSCI_WRAP_WORD)
 
695
        submenu->Check(id_et_WordWrap,true);
 
696
 
 
697
    submenu->AppendCheckItem( id_et_CharWrap, _( "Char wrap" ), _( "Wrap char" ) );
 
698
    if (control->GetWrapMode()==wxSCI_WRAP_CHAR)
 
699
        submenu->Check(id_et_CharWrap,true);
 
700
 
 
701
    submenu->AppendCheckItem( id_et_ShowLineNumbers, _( "Show Line Numbers" ), _( "Show Line Numbers" ) );
 
702
    if (control->GetMarginWidth(0)>0)
 
703
        submenu->Check(id_et_ShowLineNumbers,true);
 
704
 
 
705
    submenu->AppendSeparator();
 
706
 
 
707
    submenu->AppendCheckItem( id_et_TabChar, _( "Use Tab Character" ), _( "Use Tab Character" ) );
 
708
    if (control->GetUseTabs())
 
709
        submenu->Check(id_et_TabChar,true);
 
710
 
 
711
    submenu->AppendCheckItem( id_et_TabIndent, _( "Tab Indents" ), _( "Tab Indents" ) );
 
712
    if (control->GetTabIndents())
 
713
        submenu->Check(id_et_TabIndent,true);
 
714
 
 
715
    wxMenu *tabsizemenu=new wxMenu();
 
716
    tabsizemenu->AppendRadioItem( id_et_TabSize2, _( "2" ), _( "Tab Width of 2" ) );
 
717
    if (control->GetTabWidth()==2)
 
718
        tabsizemenu->Check(id_et_TabSize2,true);
 
719
    tabsizemenu->AppendRadioItem( id_et_TabSize4, _( "4" ), _( "Tab Width of 4" ) );
 
720
    if (control->GetTabWidth()==4)
 
721
        tabsizemenu->Check(id_et_TabSize4,true);
 
722
    tabsizemenu->AppendRadioItem( id_et_TabSize6, _( "6" ), _( "Tab Width of 6" ) );
 
723
    if (control->GetTabWidth()==6)
 
724
        tabsizemenu->Check(id_et_TabSize6,true);
 
725
    tabsizemenu->AppendRadioItem( id_et_TabSize8, _( "8" ), _( "Tab Width of 8" ) );
 
726
    if (control->GetTabWidth()==8)
 
727
        tabsizemenu->Check(id_et_TabSize8,true);
 
728
    submenu->Append(wxID_ANY,_("Tab Size"),tabsizemenu);
 
729
 
 
730
    submenu->AppendSeparator();
 
731
 
 
732
    wxMenu *eolmenu=new wxMenu();
 
733
    eolmenu->AppendRadioItem( id_et_EOLCRLF, _( "CR LF" ), _( "Carriage Return - Line Feed (Windows Default)" ) );
 
734
    if (control->GetEOLMode()==wxSCI_EOL_CRLF)
 
735
        eolmenu->Check(id_et_EOLCRLF,true);
 
736
    eolmenu->AppendRadioItem( id_et_EOLCR, _( "CR" ), _( "Carriage Return (Mac Default)" ) );
 
737
    if (control->GetEOLMode()==wxSCI_EOL_CR)
 
738
        eolmenu->Check(id_et_EOLCR,true);
 
739
    eolmenu->AppendRadioItem( id_et_EOLLF, _( "LF" ), _( "Line Feed (Unix Default)" ) );
 
740
    if (control->GetEOLMode()==wxSCI_EOL_LF)
 
741
        eolmenu->Check(id_et_EOLLF,true);
 
742
    submenu->Append(wxID_ANY,_("End-of-Line Mode"),eolmenu);
 
743
 
 
744
    submenu->AppendCheckItem( id_et_ShowEOL, _( "Show EOL Chars" ), _( "Show End-of-Line Characters" ) );
 
745
    if (control->GetViewEOL())
 
746
        submenu->Check(id_et_ShowEOL,true);
 
747
 
 
748
    submenu->Append( id_et_StripTrailingBlanks, _( "Strip Trailing Blanks Now" ), _( "Strip trailing blanks from each line" ) );
 
749
 
 
750
    submenu->Append( id_et_EnsureConsistentEOL, _( "Make EOLs Consistent Now" ), _( "Convert End-of-Line Characters to the Active Setting" ) );
 
751
 
 
752
    menu->Append(wxID_ANY, _T("Editor Tweaks"), submenu);
 
753
#endif
 
754
}
 
755
 
 
756
void EditorTweaks::OnWordWrap(wxCommandEvent &/*event*/)
 
757
{
 
758
    cbStyledTextCtrl* control = GetSafeControl();
 
759
    if (!control)
 
760
        return;
 
761
 
 
762
    bool enabled = control->GetWrapMode() == wxSCI_WRAP_WORD;
 
763
 
 
764
    if (enabled)
 
765
        control->SetWrapMode(wxSCI_WRAP_NONE);
 
766
    else
 
767
        control->SetWrapMode(wxSCI_WRAP_WORD);
 
768
}
 
769
 
 
770
void EditorTweaks::OnCharWrap(wxCommandEvent &/*event*/)
 
771
{
 
772
    cbStyledTextCtrl* control = GetSafeControl();
 
773
    if (!control)
 
774
        return;
 
775
 
 
776
    bool enabled = control->GetWrapMode() == wxSCI_WRAP_CHAR;
 
777
 
 
778
    if (enabled)
 
779
        control->SetWrapMode(wxSCI_WRAP_NONE);
 
780
    else
 
781
        control->SetWrapMode(wxSCI_WRAP_CHAR);
 
782
}
 
783
 
 
784
void EditorTweaks::OnShowLineNumbers(wxCommandEvent &/*event*/)
 
785
{
 
786
    cbStyledTextCtrl* control = GetSafeControl();
 
787
 
 
788
    bool enabled=control->GetMarginWidth(0)>0;
 
789
 
 
790
//    bool old_state=mgr->ReadBool(_T("/show_line_numbers"), true);
 
791
//    mgr->Write(_T("/show_line_numbers"), !enabled);
 
792
//    ed->SetEditorStyleAfterFileOpen();
 
793
//    mgr->Write(_T("/show_line_numbers"), old_state);
 
794
 
 
795
    if (enabled)
 
796
        control->SetMarginWidth(0, 0);
 
797
    else
 
798
    {
 
799
        ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("editor"));
 
800
        int pixelWidth = control->TextWidth(wxSCI_STYLE_LINENUMBER, _T("9"));
 
801
 
 
802
        if (cfg->ReadBool(_T("/margin/dynamic_width"), false))
 
803
        {
 
804
            int lineNumWidth = 1;
 
805
            int lineCount = control->GetLineCount();
 
806
 
 
807
            while (lineCount >= 10)
 
808
            {
 
809
                lineCount /= 10;
 
810
                ++lineNumWidth;
 
811
            }
 
812
 
 
813
            control->SetMarginWidth(0, 6 + lineNumWidth * pixelWidth);
 
814
        }
 
815
        else
 
816
            control->SetMarginWidth(0, 6 + cfg->ReadInt(_T("/margin/width_chars"), 6) * pixelWidth);
 
817
    }
 
818
}
 
819
 
 
820
void EditorTweaks::OnTabChar(wxCommandEvent &/*event*/)
 
821
{
 
822
    cbStyledTextCtrl* control = GetSafeControl();
 
823
    if (!control)
 
824
        return;
 
825
 
 
826
    control->SetUseTabs(!control->GetUseTabs());
 
827
}
 
828
 
 
829
void EditorTweaks::OnTabIndent(wxCommandEvent &/*event*/)
 
830
{
 
831
    cbStyledTextCtrl* control = GetSafeControl();
 
832
    if (!control)
 
833
        return;
 
834
 
 
835
    control->SetTabIndents(!control->GetTabIndents());
 
836
}
 
837
 
 
838
void EditorTweaks::OnTabSize2(wxCommandEvent &/*event*/)
 
839
{
 
840
    cbStyledTextCtrl* control = GetSafeControl();
 
841
    if (!control)
 
842
        return;
 
843
 
 
844
    control->SetTabWidth(2);
 
845
}
 
846
 
 
847
void EditorTweaks::OnTabSize4(wxCommandEvent &/*event*/)
 
848
{
 
849
    cbStyledTextCtrl* control = GetSafeControl();
 
850
    if (!control)
 
851
        return;
 
852
 
 
853
    control->SetTabWidth(4);
 
854
}
 
855
 
 
856
void EditorTweaks::OnTabSize6(wxCommandEvent &/*event*/)
 
857
{
 
858
    cbStyledTextCtrl* control = GetSafeControl();
 
859
    if (!control)
 
860
        return;
 
861
 
 
862
    control->SetTabWidth(6);
 
863
}
 
864
 
 
865
void EditorTweaks::OnTabSize8(wxCommandEvent &/*event*/)
 
866
{
 
867
    cbStyledTextCtrl* control = GetSafeControl();
 
868
    if (!control)
 
869
        return;
 
870
 
 
871
    control->SetTabWidth(8);
 
872
}
 
873
 
 
874
void EditorTweaks::OnMakeIndentsConsistent(wxCommandEvent& /*event*/)
 
875
{
 
876
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
 
877
    if (!ed)
 
878
        return;
 
879
 
 
880
    MakeIndentsConsistent(ed);
 
881
}
 
882
 
 
883
void EditorTweaks::MakeIndentsConsistent(cbEditor* ed)
 
884
{
 
885
    cbStyledTextCtrl* stc = ed->GetControl();
 
886
 
 
887
    const bool useTab     = stc->GetUseTabs();
 
888
    const int  tabWidth   = stc->GetTabWidth();
 
889
    const int  maxLines   = stc->GetLineCount();
 
890
    bool  changed         = false;
 
891
    for (int curLine = 0; curLine < maxLines; ++curLine)
 
892
    {
 
893
        const wxString curInd = ed->GetLineIndentString(curLine);
 
894
        wxString indent = curInd;
 
895
        if (useTab)
 
896
            indent.Replace(wxString(wxT(' '), tabWidth), wxT("\t"));
 
897
        else
 
898
            indent.Replace(wxT("\t"), wxString(wxT(' '), tabWidth));
 
899
        if (indent != curInd)
 
900
        {
 
901
            if (!changed) // all changes in a single undo step
 
902
            {
 
903
                stc->BeginUndoAction();
 
904
                changed = true;
 
905
            }
 
906
            stc->SetTargetStart(stc->PositionFromLine(curLine));
 
907
            stc->SetTargetEnd(stc->PositionFromLine(curLine) + curInd.Length());
 
908
            stc->ReplaceTarget(indent);
 
909
        }
 
910
    }
 
911
    if (changed)
 
912
        stc->EndUndoAction();
 
913
}
 
914
 
 
915
void EditorTweaks::OnShowWhitespaceChars(wxCommandEvent &event)
 
916
{
 
917
    cbStyledTextCtrl* control = GetSafeControl();
 
918
    if (control)
 
919
        control->SetViewWhiteSpace(event.IsChecked() ? wxSCI_WS_VISIBLEALWAYS : wxSCI_WS_INVISIBLE);
 
920
}
 
921
 
 
922
void EditorTweaks::OnShowEOL(wxCommandEvent &/*event*/)
 
923
{
 
924
    cbStyledTextCtrl* control = GetSafeControl();
 
925
    if (!control)
 
926
        return;
 
927
 
 
928
    control->SetViewEOL(!control->GetViewEOL());
 
929
}
 
930
 
 
931
void EditorTweaks::OnStripTrailingBlanks(wxCommandEvent &/*event*/)
 
932
{
 
933
    cbStyledTextCtrl* control = GetSafeControl();
 
934
    if (!control)
 
935
            return;
 
936
 
 
937
    StripTrailingBlanks(control);
 
938
}
 
939
 
 
940
void EditorTweaks::StripTrailingBlanks(cbStyledTextCtrl* control)
 
941
{
 
942
    int maxLines = control->GetLineCount();
 
943
    control->BeginUndoAction();
 
944
    for (int line = 0; line < maxLines; line++)
 
945
    {
 
946
        int lineStart = control->PositionFromLine(line);
 
947
        int lineEnd = control->GetLineEndPosition(line);
 
948
        int i = lineEnd-1;
 
949
        wxChar ch = (wxChar)(control->GetCharAt(i));
 
950
        while ((i >= lineStart) && ((ch == _T(' ')) || (ch == _T('\t'))))
 
951
        {
 
952
            i--;
 
953
            ch = (wxChar)(control->GetCharAt(i));
 
954
        }
 
955
        if (i < (lineEnd-1))
 
956
        {
 
957
            control->SetTargetStart(i+1);
 
958
            control->SetTargetEnd(lineEnd);
 
959
            control->ReplaceTarget(_T(""));
 
960
        }
 
961
    }
 
962
    control->EndUndoAction();
 
963
}
 
964
 
 
965
void EditorTweaks::OnEnsureConsistentEOL(wxCommandEvent &/*event*/)
 
966
{
 
967
    cbStyledTextCtrl* control = GetSafeControl();
 
968
    if (!control)
 
969
            return;
 
970
 
 
971
    control->ConvertEOLs(control->GetEOLMode());
 
972
}
 
973
 
 
974
void EditorTweaks::OnEOLCRLF(wxCommandEvent &/*event*/)
 
975
{
 
976
    cbStyledTextCtrl* control = GetSafeControl();
 
977
    if (!control)
 
978
        return;;
 
979
 
 
980
    control->SetEOLMode(wxSCI_EOL_CRLF);
 
981
}
 
982
 
 
983
void EditorTweaks::OnEOLCR(wxCommandEvent &/*event*/)
 
984
{
 
985
    cbStyledTextCtrl* control = GetSafeControl();
 
986
    if (!control)
 
987
        return;
 
988
 
 
989
    control->SetEOLMode(wxSCI_EOL_CR);
 
990
}
 
991
 
 
992
void EditorTweaks::OnEOLLF(wxCommandEvent &/*event*/)
 
993
{
 
994
    cbStyledTextCtrl* control = GetSafeControl();
 
995
    if (!control)
 
996
        return;
 
997
 
 
998
    control->SetEOLMode(wxSCI_EOL_LF);
 
999
}
 
1000
 
 
1001
void EditorTweaks::OnFold(wxCommandEvent &event)
 
1002
{
 
1003
    int level=event.GetId()-id_et_Fold1;
 
1004
    Manager::Get()->GetLogManager()->DebugLog(wxString::Format(_("Fold at level %i"),level));
 
1005
    DoFoldAboveLevel(level,1);
 
1006
}
 
1007
 
 
1008
void EditorTweaks::OnUnfold(wxCommandEvent &event)
 
1009
{
 
1010
    int level=event.GetId()-id_et_Unfold1;
 
1011
    Manager::Get()->GetLogManager()->DebugLog(wxString::Format(_("Unfold at level %i"),level));
 
1012
    DoFoldAboveLevel(level,0);
 
1013
}
 
1014
 
 
1015
 
 
1016
/**     Fold/Unfold/Toggle all folds in the givel level.
 
1017
        \param  level   Level number of folding, starting from 0.
 
1018
        \param  fold    Type of folding action requested:       \n
 
1019
        -       0 = Unfold.
 
1020
        -       1 = Fold.
 
1021
*/
 
1022
void EditorTweaks::DoFoldAboveLevel(int level, int fold)
 
1023
{
 
1024
    cbStyledTextCtrl* control = GetSafeControl();
 
1025
    if (!control)
 
1026
        return;
 
1027
 
 
1028
    level+=wxSCI_FOLDLEVELBASE;
 
1029
 
 
1030
    control->Colourise(0, -1); // the *most* important part!
 
1031
 
 
1032
        // Scan all file lines searching for the specified folding level.
 
1033
    int count = control->GetLineCount();
 
1034
    for (int line = 0; line <= count; ++line)
 
1035
    {
 
1036
        int line_level_data = control->GetFoldLevel(line);
 
1037
        if (!(line_level_data & wxSCI_FOLDLEVELHEADERFLAG))
 
1038
            continue;
 
1039
        const int line_level = line_level_data & wxSCI_FOLDLEVELNUMBERMASK;
 
1040
 
 
1041
        const bool IsExpanded = control->GetFoldExpanded(line);
 
1042
 
 
1043
        // If a fold/unfold request is issued when the block is already
 
1044
        // folded/unfolded, ignore the request.
 
1045
        if (line_level<=level)
 
1046
        {
 
1047
            if (IsExpanded)
 
1048
                continue;
 
1049
        }
 
1050
        else
 
1051
        {
 
1052
            if ((fold==0 && IsExpanded) || (fold ==1 && !IsExpanded))
 
1053
                continue;
 
1054
        }
 
1055
        control->ToggleFold(line);
 
1056
    }
 
1057
}
 
1058
 
 
1059
void EditorTweaks::OnAlign(wxCommandEvent& event)
 
1060
{
 
1061
    int id = event.GetId();
 
1062
    for ( unsigned int i = 0 ; i < AlignerMenuEntries.size(); i++)
 
1063
    {
 
1064
        if ( AlignerMenuEntries[i].id == id )
 
1065
        {
 
1066
            DoAlign(i);
 
1067
            break;
 
1068
        }
 
1069
    }
 
1070
}
 
1071
void EditorTweaks::DoAlign(unsigned int idx)
 
1072
{
 
1073
    if (idx >= AlignerMenuEntries.size())
 
1074
        return;
 
1075
    AlignToString(AlignerMenuEntries[idx].ArgumentString);
 
1076
    AlignerMenuEntries[idx].UsageCount ++;
 
1077
 
 
1078
    AlignerLastUsedIdx = idx;
 
1079
    AlignerLastUsedAuto = false;
 
1080
    AlignerLastUsed = true;
 
1081
}
 
1082
void EditorTweaks::OnAlignOthers(wxCommandEvent& /*event*/)
 
1083
{
 
1084
    wxString NewAlignmentString;
 
1085
    wxString NewAlignmentStringName;
 
1086
    bool NewCharacter = true;
 
1087
 
 
1088
    // create the name and call the first DialogBox
 
1089
    const wxString MessageArgumentString = _("Insert a new character");
 
1090
    const wxString CaptionArgumentString = _("New character");
 
1091
    NewAlignmentString = wxGetTextFromUser( MessageArgumentString, CaptionArgumentString );
 
1092
    if (NewAlignmentString !=_T(""))
 
1093
    {
 
1094
        // check if the new character is equal as an exist
 
1095
        unsigned int i;
 
1096
        for ( i = 0 ; i < AlignerMenuEntries.size(); i++)
 
1097
        {
 
1098
            if (AlignerMenuEntries[i].ArgumentString == NewAlignmentString)
 
1099
            {
 
1100
                NewCharacter = false;
 
1101
                break;
 
1102
            }
 
1103
        }
 
1104
 
 
1105
        if (NewCharacter)
 
1106
        {
 
1107
            AlignerMenuEntry e;
 
1108
            e.UsageCount = 0;
 
1109
            e.id = wxNewId();
 
1110
            e.ArgumentString = NewAlignmentString;
 
1111
            AlignerMenuEntries.push_back(e);
 
1112
            Connect(e.id, wxEVT_COMMAND_MENU_SELECTED,  wxCommandEventHandler(EditorTweaks::OnAlign) );
 
1113
        }
 
1114
 
 
1115
        // create the name and call the second DialogBox
 
1116
        const wxString MessageName = _("Insert a name for the (new) character");
 
1117
        const wxString CaptionName = NewAlignmentString;
 
1118
        NewAlignmentStringName = wxGetTextFromUser( MessageName, CaptionName , AlignerMenuEntries[i].MenuName);
 
1119
        if (NewAlignmentStringName != _T(""))
 
1120
            AlignerMenuEntries[i].MenuName = NewAlignmentStringName;
 
1121
 
 
1122
        AlignToString(AlignerMenuEntries[i].ArgumentString);
 
1123
        AlignerMenuEntries[i].UsageCount++;
 
1124
    }
 
1125
}
 
1126
 
 
1127
void EditorTweaks::OnAlignLast(cb_unused wxCommandEvent& event)
 
1128
{
 
1129
    if(!AlignerLastUsed)
 
1130
        return;
 
1131
 
 
1132
    if (AlignerLastUsedAuto)
 
1133
        DoAlignAuto();
 
1134
    else
 
1135
        DoAlign(AlignerLastUsedIdx);
 
1136
}
 
1137
 
 
1138
void EditorTweaks::OnAlignAuto(cb_unused wxCommandEvent& event)
 
1139
{
 
1140
    DoAlignAuto();
 
1141
}
 
1142
void EditorTweaks::DoAlignAuto()
 
1143
{
 
1144
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
 
1145
    if (!ed)
 
1146
        return;
 
1147
    cbStyledTextCtrl* stc = ed->GetControl();
 
1148
    if (!stc)
 
1149
        return;
 
1150
 
 
1151
    int line_start = wxSCI_INVALID_POSITION;
 
1152
    int line_end   = wxSCI_INVALID_POSITION;
 
1153
    if (!GetSelectionLines(line_start, line_end))
 
1154
        return;
 
1155
    wxArrayString lines;
 
1156
    for (int i = line_start; i <= line_end; ++i)
 
1157
        lines.Add(stc->GetLine(i));
 
1158
    if (lines.GetCount() < 2)
 
1159
        return;
 
1160
    int lexer = stc->GetLexer();
 
1161
    wxArrayString out;
 
1162
    for (size_t i = 0; i < lines.GetCount(); ++i)
 
1163
    {
 
1164
        lines[i].Replace(wxT("\t"), wxT(" "));
 
1165
        // buffer assignment operators and commas in C++
 
1166
        if (lexer == wxSCI_LEX_CPP)
 
1167
        {
 
1168
            const wxString op = wxT("=<>!+-*/%&^| "); // do not split compound operators
 
1169
            for (int j = lines[i].Length() - 2; j >= 0; --j)
 
1170
            {
 
1171
                if (   lines[i][j] == wxT(',')
 
1172
                    || (lines[i][j] == wxT('=') && lines[i][j + 1] != wxT('='))
 
1173
                    || (lines[i][j + 1] == wxT('=') && op.Find(lines[i][j]) == wxNOT_FOUND) )
 
1174
                {
 
1175
                    lines[i].insert(j + 1, wxT(' '));
 
1176
                }
 
1177
            }
 
1178
        }
 
1179
        // initialize output strings with their current indentation
 
1180
        out.Add(ed->GetLineIndentString(line_start + i));
 
1181
    }
 
1182
    // loop through number of columns
 
1183
    size_t numCols = 1;
 
1184
    for (size_t i = 0; i < numCols; ++i)
 
1185
    {
 
1186
        // add the next token
 
1187
        for (size_t j = 0; j < lines.GetCount(); ++j)
 
1188
        {
 
1189
            wxArrayString lnParts = GetArrayFromString(lines[j], wxT(" "));
 
1190
            if (i < lnParts.GetCount())
 
1191
                out[j].Append(lnParts[i]);
 
1192
            // set actual number of columns
 
1193
            if (lnParts.GetCount() > numCols)
 
1194
                numCols = lnParts.GetCount();
 
1195
        }
 
1196
        // find the column size
 
1197
        size_t colPos = 0;
 
1198
        for (size_t j = 0; j < out.GetCount(); ++j)
 
1199
        {
 
1200
            if (out[j].Length() > colPos)
 
1201
                colPos = out[j].Length();
 
1202
        }
 
1203
        // buffer output lines to column size + 1
 
1204
        for (size_t j = 0; j < out.GetCount(); ++j)
 
1205
        {
 
1206
            while (out[j].Length() <= colPos)
 
1207
                out[j].Append(wxT(' '));
 
1208
        }
 
1209
    }
 
1210
    // replace only the lines that have been modified
 
1211
    stc->BeginUndoAction();
 
1212
    for (size_t i = 0; i < out.GetCount(); ++i)
 
1213
    {
 
1214
        stc->SetSelectionVoid(stc->PositionFromLine(line_start + i),
 
1215
                              stc->GetLineEndPosition(line_start + i));
 
1216
        if (stc->GetSelectedText() != out[i].Trim())
 
1217
            stc->ReplaceSelection(out[i]);
 
1218
    }
 
1219
    stc->LineEnd(); // remove selection (if last line was not replaced)
 
1220
    stc->EndUndoAction();
 
1221
 
 
1222
    AlignerLastUsedAuto = true;
 
1223
    AlignerLastUsed = true;
 
1224
}
 
1225
 
 
1226
void EditorTweaks::AlignToString(const wxString AlignmentString)
 
1227
{
 
1228
    cbStyledTextCtrl* control = GetSafeControl();
 
1229
    if (!control)
 
1230
        return;
 
1231
 
 
1232
    int line_start = wxSCI_INVALID_POSITION;
 
1233
    int line_end   = wxSCI_INVALID_POSITION;
 
1234
    if (GetSelectionLines(line_start, line_end))
 
1235
    {
 
1236
        // get furthest position of alignmentstring
 
1237
        size_t find_position  = wxString::npos;
 
1238
        size_t max_position   = wxString::npos;
 
1239
        int matches           = 0;
 
1240
        for (int i=line_start; i<=line_end; i++)
 
1241
        {
 
1242
            // look for string
 
1243
            find_position = control->GetLine(i).Find(AlignmentString);
 
1244
 
 
1245
            // store max position
 
1246
            if (find_position != wxString::npos)
 
1247
            {
 
1248
                matches++;
 
1249
                if ((int) find_position > (int) max_position)
 
1250
                    max_position = find_position;
 
1251
            }
 
1252
        }
 
1253
 
 
1254
        // if string has been found more than once
 
1255
        if (matches > 1)
 
1256
        {
 
1257
            // loop through lines
 
1258
            wxString replacement_text = _T("");
 
1259
            wxString current_line     = _T("");
 
1260
            int spacing_diff          = 0;
 
1261
            for (int i=line_start; i<=line_end; i++)
 
1262
            {
 
1263
                // get line
 
1264
                current_line = control->GetLine(i);
 
1265
                if ( i == line_end )
 
1266
                    current_line = current_line.Trim();
 
1267
 
 
1268
 
 
1269
                // look for string
 
1270
                find_position = current_line.Find(AlignmentString);
 
1271
 
 
1272
                // insert spacing
 
1273
                if (find_position != wxString::npos)
 
1274
                {
 
1275
                    spacing_diff = (int) max_position - (int) find_position;
 
1276
                    if (spacing_diff > 0)
 
1277
                    {
 
1278
                        // assemble next part of replacement string
 
1279
                        current_line = current_line.insert(find_position, GetPadding(_T(" "), spacing_diff));
 
1280
                    }
 
1281
                }
 
1282
 
 
1283
                // tack on line
 
1284
                replacement_text += current_line;
 
1285
            }
 
1286
 
 
1287
            // start undo
 
1288
            control->BeginUndoAction();
 
1289
 
 
1290
            // get character positions of true selection start and end
 
1291
            int pos_start = control->PositionFromLine(line_start);
 
1292
            int pos_end   = control->GetLineEndPosition(line_end);
 
1293
 
 
1294
            // select all lines properly
 
1295
            control->SetSelectionVoid(pos_start, pos_end);
 
1296
 
 
1297
            // replace with replacement string
 
1298
            control->ReplaceSelection(replacement_text);
 
1299
 
 
1300
            // finish undo
 
1301
            control->EndUndoAction();
 
1302
        }
 
1303
    }
 
1304
 
 
1305
}
 
1306
 
 
1307
wxString EditorTweaks::GetPadding(const wxString& Padding, const int Count)
 
1308
{
 
1309
        wxString padding = _T("");
 
1310
        for (int i=0;i<Count;i++)
 
1311
                padding += Padding;
 
1312
        return padding;
 
1313
}
 
1314
 
 
1315
bool EditorTweaks::GetSelectionLines(int& LineStart, int& LineEnd)
 
1316
{
 
1317
    bool found_lines = false;
 
1318
 
 
1319
    cbEditor* editor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
 
1320
    if ( (editor) && (editor->HasSelection()) )
 
1321
    {
 
1322
        cbStyledTextCtrl* control = editor->GetControl();
 
1323
 
 
1324
        if (control)
 
1325
        {
 
1326
            int line_start = control->GetSelectionStart();
 
1327
            int line_end   = control->GetSelectionEnd();
 
1328
 
 
1329
                        if ( (line_start != wxSCI_INVALID_POSITION) && (line_end != wxSCI_INVALID_POSITION) )
 
1330
                        {
 
1331
                                LineStart   = control->LineFromPosition(line_start);
 
1332
                                LineEnd     = control->LineFromPosition(line_end);
 
1333
                                found_lines = (line_end > line_start);
 
1334
                        }
 
1335
        }
 
1336
    }
 
1337
 
 
1338
    // done
 
1339
    return found_lines;
 
1340
}
 
1341
 
 
1342
void EditorTweaks::DoBufferEditorPos(int delta, bool isScrollTimer)
 
1343
{
 
1344
    if (m_buffer_caret == -1)
 
1345
        m_buffer_caret = Manager::Get()->GetConfigManager(wxT("EditorTweaks"))->ReadInt(wxT("/buffer_caret"), 1);
 
1346
    if (m_buffer_caret < 1) // feature disabled (selected "None" in settings)
 
1347
        return;
 
1348
 
 
1349
    cbStyledTextCtrl* stc = GetSafeControl();
 
1350
    if (!stc)
 
1351
        return;
 
1352
 
 
1353
    if (!stc || stc->AutoCompActive() || stc->LinesOnScreen() < 10) // ignore small editors
 
1354
        return;
 
1355
    const int firstVisibleLine = stc->GetFirstVisibleLine();
 
1356
    const int dist = stc->VisibleFromDocLine(stc->GetCurrentLine()) + delta - firstVisibleLine;
 
1357
    if (dist < 0 || dist > stc->LinesOnScreen()) // caret is off screen (see bug #18795)
 
1358
    {
 
1359
        if (!isScrollTimer && !m_scrollTimer.IsRunning())
 
1360
            m_scrollTimer.Start(5, wxTIMER_ONE_SHOT); // check to see if we moved into place
 
1361
        return;
 
1362
    }
 
1363
    const int buffer = (m_buffer_caret > 4 ? (stc->LinesOnScreen() >> 1) - 2 : m_buffer_caret);
 
1364
    int remaining = 0;
 
1365
    if (dist < buffer)
 
1366
    {
 
1367
        remaining = buffer - dist - 1;
 
1368
        stc->LineScroll(0, (remaining > 3 ? -2 : -1)); // scroll up
 
1369
    }
 
1370
    else if (dist >= stc->LinesOnScreen() - buffer)
 
1371
    {
 
1372
        remaining = dist + buffer - stc->LinesOnScreen();
 
1373
        stc->LineScroll(0, (remaining > 3 ? 2 : 1)); // scroll down
 
1374
    }
 
1375
    if (!m_scrollTimer.IsRunning() && remaining > 0 && firstVisibleLine != stc->GetFirstVisibleLine())
 
1376
        m_scrollTimer.Start(4 + (30 / remaining), wxTIMER_ONE_SHOT); // smooth scroll required lines
 
1377
}
 
1378
 
 
1379
void EditorTweaks::OnScrollTimer(wxTimerEvent& WXUNUSED(event))
 
1380
{
 
1381
    DoBufferEditorPos(0, true);
 
1382
}
 
1383
 
 
1384
cbStyledTextCtrl* EditorTweaks::GetSafeControl()
 
1385
{
 
1386
    if ( !IsAttached() )
 
1387
        return nullptr;
 
1388
 
 
1389
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
 
1390
    return ed ? ed->GetControl() : nullptr;
 
1391
}