~ubuntu-branches/ubuntu/oneiric/codeblocks/oneiric

« back to all changes in this revision

Viewing changes to src/sdk/editormanager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Casadevall
  • Date: 2008-07-17 04:39:23 UTC
  • Revision ID: james.westby@ubuntu.com-20080717043923-gmsy5cwkdjswghkm
Tags: upstream-8.02
ImportĀ upstreamĀ versionĀ 8.02

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 
3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 
4
 *
 
5
 * $Revision: 4909 $
 
6
 * $Id: editormanager.cpp 4909 2008-02-27 13:15:26Z mortenmacfly $
 
7
 * $HeadURL: svn://svn.berlios.de/codeblocks/tags/8.02/src/sdk/editormanager.cpp $
 
8
 */
 
9
 
 
10
#include "sdk_precomp.h"
 
11
 
 
12
#ifndef CB_PRECOMP
 
13
    #include <wx/notebook.h>
 
14
    #include <wx/menu.h>
 
15
    #include <wx/splitter.h>
 
16
    #include <wx/imaglist.h>
 
17
    #include <wx/regex.h>
 
18
    #include <wx/listctrl.h>
 
19
 
 
20
    #include "editormanager.h" // class's header file
 
21
    #include "configmanager.h"
 
22
    #include <wx/xrc/xmlres.h>
 
23
    #include "logmanager.h"
 
24
    #include "projectmanager.h"
 
25
    #include "projectfile.h"
 
26
    #include "pluginmanager.h"
 
27
    #include "manager.h"
 
28
    #include "filemanager.h"
 
29
    #include "sdk_events.h"
 
30
    #include "projectbuildtarget.h"
 
31
    #include "cbproject.h"
 
32
    #include "cbeditor.h"
 
33
    #include "globals.h"
 
34
    #include "sdk_events.h"
 
35
    #include <wx/file.h>
 
36
    #include <wx/dir.h>
 
37
#endif
 
38
#include "cbstyledtextctrl.h"
 
39
 
 
40
#include <wx/bmpbuttn.h>
 
41
#include <wx/progdlg.h>
 
42
#include <wx/fontutil.h>
 
43
 
 
44
#include "editorcolourset.h"
 
45
#include "editorconfigurationdlg.h"
 
46
#include "finddlg.h"
 
47
#include "replacedlg.h"
 
48
#include "confirmreplacedlg.h"
 
49
#include "filefilters.h"
 
50
#include "searchresultslog.h"
 
51
#include "projectfileoptionsdlg.h"
 
52
 
 
53
#include "wx/wxFlatNotebook/wxFlatNotebook.h"
 
54
 
 
55
template<> EditorManager* Mgr<EditorManager>::instance = 0;
 
56
template<> bool  Mgr<EditorManager>::isShutdown = false;
 
57
 
 
58
int ID_NBEditorManager = wxNewId();
 
59
int ID_EditorManager = wxNewId();
 
60
int idEditorManagerCheckFiles = wxNewId();
 
61
 
 
62
// static
 
63
bool EditorManager::s_CanShutdown = true;
 
64
 
 
65
struct cbFindReplaceData
 
66
{
 
67
    int start;
 
68
    int end;
 
69
    wxString findText;
 
70
    wxString replaceText;
 
71
    bool initialreplacing;
 
72
    bool findInFiles;
 
73
    bool delOldSearches;
 
74
    bool matchWord;
 
75
    bool startWord;
 
76
    bool matchCase;
 
77
    bool regEx;
 
78
    bool directionDown;
 
79
    bool originEntireScope;
 
80
    int scope;
 
81
    wxString searchPath;
 
82
    wxString searchMask;
 
83
    bool recursiveSearch;
 
84
    bool hiddenSearch;
 
85
    bool NewSearch;     //!< only true when a new search has been started
 
86
    int SearchInSelectionStart; //!< keep track of the start of a 'search' selection
 
87
    int SearchInSelectionEnd;  //!< keep track of the end of a 'search' selection
 
88
    bool autoWrapSearch;
 
89
    bool findUsesSelectedText;
 
90
};
 
91
 
 
92
static const int idNBTabSplitHorz = wxNewId();
 
93
static const int idNBTabSplitVert = wxNewId();
 
94
static const int idNBTabUnsplit = wxNewId();
 
95
static const int idNBTabClose = wxNewId();
 
96
static const int idNBTabCloseAll = wxNewId();
 
97
static const int idNBTabCloseAllOthers = wxNewId();
 
98
static const int idNBTabSave = wxNewId();
 
99
static const int idNBTabSaveAll = wxNewId();
 
100
static const int idNBSwapHeaderSource = wxNewId();
 
101
static const int idNBTabTop = wxNewId();
 
102
static const int idNBTabBottom = wxNewId();
 
103
static const int idNBProperties = wxNewId();
 
104
static const int idNB = wxNewId();
 
105
 
 
106
/** *******************************************************
 
107
  * struct EditorManagerInternalData                      *
 
108
  * This is the private data holder for the EditorManager *
 
109
  * All data not relevant to other classes should go here *
 
110
  ********************************************************* */
 
111
 
 
112
struct EditorManagerInternalData
 
113
{
 
114
    /* Methods */
 
115
 
 
116
    EditorManagerInternalData(EditorManager* owner)
 
117
            : m_pOwner(owner)
 
118
    {}
 
119
 
 
120
    /* Static data */
 
121
 
 
122
    EditorManager* m_pOwner;
 
123
    bool m_SetFocusFlag;
 
124
};
 
125
 
 
126
// *********** End of EditorManagerInternalData **********
 
127
 
 
128
 
 
129
BEGIN_EVENT_TABLE(EditorManager, wxEvtHandler)
 
130
    EVT_APP_STARTUP_DONE(EditorManager::OnAppDoneStartup)
 
131
    EVT_APP_START_SHUTDOWN(EditorManager::OnAppStartShutdown)
 
132
    EVT_FLATNOTEBOOK_PAGE_CHANGED(ID_NBEditorManager, EditorManager::OnPageChanged)
 
133
    EVT_FLATNOTEBOOK_PAGE_CHANGING(ID_NBEditorManager, EditorManager::OnPageChanging)
 
134
    EVT_FLATNOTEBOOK_PAGE_CLOSING(ID_NBEditorManager, EditorManager::OnPageClosing)
 
135
    EVT_FLATNOTEBOOK_CONTEXT_MENU(ID_NBEditorManager, EditorManager::OnPageContextMenu)
 
136
    EVT_MENU(idNBTabSplitHorz, EditorManager::OnGenericContextMenuHandler)
 
137
    EVT_MENU(idNBTabSplitVert, EditorManager::OnGenericContextMenuHandler)
 
138
    EVT_MENU(idNBTabUnsplit, EditorManager::OnGenericContextMenuHandler)
 
139
    EVT_MENU(idNBTabTop, EditorManager::OnTabPosition)
 
140
    EVT_MENU(idNBTabBottom, EditorManager::OnTabPosition)
 
141
    EVT_MENU(idNBTabClose, EditorManager::OnClose)
 
142
    EVT_MENU(idNBTabCloseAll, EditorManager::OnCloseAll)
 
143
    EVT_MENU(idNBTabCloseAllOthers, EditorManager::OnCloseAllOthers)
 
144
    EVT_MENU(idNBTabSave, EditorManager::OnSave)
 
145
    EVT_MENU(idNBTabSaveAll, EditorManager::OnSaveAll)
 
146
    EVT_MENU(idNBSwapHeaderSource, EditorManager::OnSwapHeaderSource)
 
147
    EVT_MENU(idNBProperties, EditorManager::OnProperties)
 
148
    EVT_MENU(idEditorManagerCheckFiles, EditorManager::OnCheckForModifiedFiles)
 
149
END_EVENT_TABLE()
 
150
 
 
151
// class constructor
 
152
EditorManager::EditorManager()
 
153
        : m_pNotebook(0L),
 
154
        m_LastFindReplaceData(0L),
 
155
        m_pSearchLog(0),
 
156
        m_SearchLogIndex(-1),
 
157
        m_SashPosition(150), // no longer used
 
158
        m_isCheckingForExternallyModifiedFiles(false)
 
159
{
 
160
    m_pData = new EditorManagerInternalData(this);
 
161
 
 
162
    m_pNotebook = new wxFlatNotebook(Manager::Get()->GetAppWindow(), ID_NBEditorManager, wxDefaultPosition, wxDefaultSize, wxNO_FULL_REPAINT_ON_RESIZE | wxCLIP_CHILDREN);
 
163
    m_pNotebook->SetWindowStyleFlag(Manager::Get()->GetConfigManager(_T("app"))->ReadInt(_T("/environment/editor_tabs_style"), wxFNB_DEFAULT_STYLE | wxFNB_MOUSE_MIDDLE_CLOSES_TABS));
 
164
 
 
165
        Manager::Get()->GetLogManager()->DebugLog(_T("Initialize EditColourSet ....."));
 
166
    m_Theme = new EditorColourSet(Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/colour_sets/active_colour_set"), COLORSET_DEFAULT));
 
167
        Manager::Get()->GetLogManager()->DebugLog(_T("Initialize EditColourSet: done."));
 
168
 
 
169
    Manager::Get()->GetAppWindow()->PushEventHandler(this);
 
170
 
 
171
    CreateSearchLog();
 
172
    LoadAutoComplete();
 
173
    m_zoom = Manager::Get()->GetConfigManager(_T("editor"))->ReadInt(_T("/zoom"));
 
174
}
 
175
 
 
176
// class destructor
 
177
EditorManager::~EditorManager()
 
178
{
 
179
    SaveAutoComplete();
 
180
 
 
181
    CodeBlocksLogEvent evt(cbEVT_REMOVE_LOG_WINDOW, m_pSearchLog);
 
182
    Manager::Get()->ProcessEvent(evt);
 
183
 
 
184
    delete m_Theme;
 
185
    delete m_LastFindReplaceData;
 
186
    delete m_pData;
 
187
    Manager::Get()->GetConfigManager(_T("editor"))->Write(_T("/zoom"), m_zoom);
 
188
} // end of destructor
 
189
 
 
190
void EditorManager::CreateMenu(wxMenuBar* menuBar)
 
191
{
 
192
}
 
193
 
 
194
void EditorManager::ReleaseMenu(wxMenuBar* menuBar)
 
195
{
 
196
}
 
197
 
 
198
void EditorManager::Configure()
 
199
{
 
200
    // editor lexers loading takes some time; better reflect this with a hourglass
 
201
    wxBeginBusyCursor();
 
202
 
 
203
    EditorConfigurationDlg dlg(Manager::Get()->GetAppWindow());
 
204
    PlaceWindow(&dlg);
 
205
 
 
206
    // done, restore pointer
 
207
    wxEndBusyCursor();
 
208
 
 
209
    if (dlg.ShowModal() == wxID_OK)
 
210
    {
 
211
        // tell all open editors to re-create their styles
 
212
        for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
213
        {
 
214
            cbEditor* ed = InternalGetBuiltinEditor(i);
 
215
            if (ed)
 
216
            {
 
217
                bool saveSuccess = ed->SaveFoldState(); //First Save the old fold levels
 
218
                ed->SetEditorStyle();
 
219
                if(saveSuccess)
 
220
                {
 
221
                    ed->FixFoldState(); //Compare old fold levels with new and change the bugs
 
222
                }
 
223
            }
 
224
        }
 
225
    }
 
226
} // end of Configure
 
227
 
 
228
void EditorManager::CreateSearchLog()
 
229
{
 
230
        if (Manager::IsBatchBuild())
 
231
                return;
 
232
 
 
233
    wxArrayInt widths;
 
234
    wxArrayString titles;
 
235
    titles.Add(_("File"));
 
236
    titles.Add(_("Line"));
 
237
    titles.Add(_("Text"));
 
238
    widths.Add(128);
 
239
    widths.Add(48);
 
240
    widths.Add(640);
 
241
 
 
242
    wxString prefix = ConfigManager::GetDataFolder() + _T("/images/16x16/");
 
243
    wxBitmap * bmp = new wxBitmap(cbLoadBitmap(prefix + _T("filefind.png"), wxBITMAP_TYPE_PNG));
 
244
 
 
245
    m_pSearchLog = new SearchResultsLog(titles, widths);
 
246
    CodeBlocksLogEvent evt(cbEVT_ADD_LOG_WINDOW, m_pSearchLog, _("Search results"), bmp);
 
247
    Manager::Get()->ProcessEvent(evt);
 
248
}
 
249
 
 
250
void EditorManager::LogSearch(const wxString& file, int line, const wxString& lineText)
 
251
{
 
252
    wxArrayString values;
 
253
    wxString lineTextL;
 
254
    wxString lineStr;
 
255
 
 
256
    // line number -1 is used for empty string
 
257
    if( line != -1)
 
258
    {
 
259
        lineStr.Printf(_T("%d"), line);
 
260
    }
 
261
    else
 
262
    {
 
263
        lineStr.Printf(_T(" "));
 
264
    }
 
265
    lineTextL = lineText;
 
266
    lineTextL.Replace(_T("\t"), _T(" "));
 
267
    lineTextL.Replace(_T("\r"), _T(" "));
 
268
    lineTextL.Replace(_T("\n"), _T(" "));
 
269
    lineTextL.Trim(false);
 
270
    lineTextL.Trim(true);
 
271
 
 
272
    values.Add(file);
 
273
    values.Add(lineStr);
 
274
    values.Add(lineTextL);
 
275
 
 
276
    m_pSearchLog->Append(values, line == -1 ? Logger::caption : Logger::info);
 
277
}
 
278
 
 
279
void EditorManager::LoadAutoComplete()
 
280
{
 
281
    m_AutoCompleteMap.clear();
 
282
    wxArrayString list = Manager::Get()->GetConfigManager(_T("editor"))->EnumerateSubPaths(_T("/auto_complete"));
 
283
    for (unsigned int i = 0; i < list.GetCount(); ++i)
 
284
    {
 
285
        wxString name = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/auto_complete/") + list[i] + _T("/name"), wxEmptyString);
 
286
        wxString code = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/auto_complete/") + list[i] + _T("/code"), wxEmptyString);
 
287
        if (name.IsEmpty() || code.IsEmpty())
 
288
            continue;
 
289
        // convert non-printable chars to printable
 
290
        code.Replace(_T("\\n"), _T("\n"));
 
291
        code.Replace(_T("\\r"), _T("\r"));
 
292
        code.Replace(_T("\\t"), _T("\t"));
 
293
        m_AutoCompleteMap[name] = code;
 
294
    }
 
295
 
 
296
    if (m_AutoCompleteMap.size() == 0)
 
297
    {
 
298
        // default auto-complete items
 
299
        m_AutoCompleteMap[_T("if")] = _T("if (|)\n\t;");
 
300
        m_AutoCompleteMap[_T("ifb")] = _T("if (|)\n{\n\t\n}");
 
301
        m_AutoCompleteMap[_T("ife")] = _T("if (|)\n{\n\t\n}\nelse\n{\n\t\n}");
 
302
        m_AutoCompleteMap[_T("ifei")] = _T("if (|)\n{\n\t\n}\nelse if ()\n{\n\t\n}\nelse\n{\n\t\n}");
 
303
        m_AutoCompleteMap[_T("guard")] = _T("#ifndef $(Guard token)\n#define $(Guard token)\n\n|\n\n#endif // $(Guard token)\n");
 
304
        m_AutoCompleteMap[_T("while")] = _T("while (|)\n\t;");
 
305
        m_AutoCompleteMap[_T("whileb")] = _T("while (|)\n{\n\t\n}");
 
306
        m_AutoCompleteMap[_T("switch")] = _T("switch (|)\n{\n\tcase :\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n}\n");
 
307
        m_AutoCompleteMap[_T("for")] = _T("for (|; ; )\n\t;");
 
308
        m_AutoCompleteMap[_T("forb")] = _T("for (|; ; )\n{\n\t\n}");
 
309
        m_AutoCompleteMap[_T("class")] = _T("class $(Class name)|\n{\n\tpublic:\n\t\t$(Class name)();\n\t\t~$(Class name)();\n\tprotected:\n\t\t\n\tprivate:\n\t\t\n};\n");
 
310
        m_AutoCompleteMap[_T("struct")] = _T("struct |\n{\n\t\n};\n");
 
311
    }
 
312
 
 
313
    // date and time macros
 
314
    // these are auto-added if they 're found to be missing
 
315
    const wxString timeAndDate[9][2] =
 
316
    {
 
317
        { _T("tday"), _T("$TDAY") },
 
318
        { _T("tdayu"), _T("$TDAY_UTC") },
 
319
        { _T("today"), _T("$TODAY") },
 
320
        { _T("todayu"), _T("$TODAY_UTC") },
 
321
        { _T("now"), _T("$NOW") },
 
322
        { _T("nowl"), _T("$NOW_L") },
 
323
        { _T("nowu"), _T("$NOW_UTC") },
 
324
        { _T("nowlu"), _T("$NOW_L_UTC") },
 
325
        { _T("wdu"), _T("$WEEKDAY_UTC") },
 
326
    };
 
327
    for (int i = 0; i < 9; ++i)
 
328
    {
 
329
        if (m_AutoCompleteMap.find(timeAndDate[i][0]) == m_AutoCompleteMap.end())
 
330
            m_AutoCompleteMap[timeAndDate[i][0]] = timeAndDate[i][1];
 
331
    }
 
332
}
 
333
 
 
334
void EditorManager::SaveAutoComplete()
 
335
{
 
336
    Manager::Get()->GetConfigManager(_T("editor"))->DeleteSubPath(_T("/auto_complete"));
 
337
    AutoCompleteMap::iterator it;
 
338
    int count = 0;
 
339
    for (it = m_AutoCompleteMap.begin(); it != m_AutoCompleteMap.end(); ++it)
 
340
    {
 
341
        wxString code = it->second;
 
342
        // convert non-printable chars to printable
 
343
        code.Replace(_T("\n"), _T("\\n"));
 
344
        code.Replace(_T("\r"), _T("\\r"));
 
345
        code.Replace(_T("\t"), _T("\\t"));
 
346
 
 
347
        ++count;
 
348
        wxString key;
 
349
        key.Printf(_T("/auto_complete/entry%d/name"), count);
 
350
        Manager::Get()->GetConfigManager(_T("editor"))->Write(key, it->first);
 
351
        key.Printf(_T("/auto_complete/entry%d/code"), count);
 
352
        Manager::Get()->GetConfigManager(_T("editor"))->Write(key, code);
 
353
    }
 
354
}
 
355
 
 
356
int EditorManager::GetEditorsCount()
 
357
{
 
358
    return m_pNotebook->GetPageCount();
 
359
}
 
360
 
 
361
EditorBase* EditorManager::InternalGetEditorBase(int page)
 
362
{
 
363
    EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(page));
 
364
    return eb;
 
365
}
 
366
 
 
367
cbEditor* EditorManager::InternalGetBuiltinEditor(int page)
 
368
{
 
369
    EditorBase* eb = InternalGetEditorBase(page);
 
370
    if (eb && eb->IsBuiltinEditor())
 
371
        return (cbEditor*)eb;
 
372
    return 0;
 
373
}
 
374
 
 
375
cbEditor* EditorManager::GetBuiltinEditor(EditorBase* eb)
 
376
{
 
377
    return eb && eb->IsBuiltinEditor() ? (cbEditor*)eb : 0;
 
378
}
 
379
 
 
380
EditorBase* EditorManager::IsOpen(const wxString& filename)
 
381
{
 
382
    wxString uFilename = UnixFilename(filename);
 
383
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
384
    {
 
385
        EditorBase* eb = InternalGetEditorBase(i);
 
386
        if (!eb)
 
387
            continue;
 
388
        wxString fname = eb->GetFilename();
 
389
 
 
390
        // MSW must use case-insensitive comparison
 
391
        if (fname.IsSameAs(uFilename, platform::windows == false) || fname.IsSameAs(g_EditorModified + uFilename, platform::windows == false))
 
392
            return eb;
 
393
    }
 
394
 
 
395
    return NULL;
 
396
}
 
397
 
 
398
EditorBase* EditorManager::GetEditor(int index)
 
399
{
 
400
    return InternalGetEditorBase(index);
 
401
}
 
402
 
 
403
void EditorManager::SetColourSet(EditorColourSet* theme)
 
404
{
 
405
    if (m_Theme)
 
406
        delete m_Theme;
 
407
 
 
408
    // copy locally
 
409
    m_Theme = new EditorColourSet(*theme);
 
410
 
 
411
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
412
    {
 
413
        cbEditor* ed = InternalGetBuiltinEditor(i);
 
414
        if (ed)
 
415
            ed->SetColourSet(m_Theme);
 
416
    }
 
417
}
 
418
 
 
419
cbEditor* EditorManager::Open(const wxString& filename, int pos, ProjectFile* data)
 
420
{
 
421
    LoaderBase* fileLdr = Manager::Get()->GetFileManager()->Load(filename);
 
422
    if (!fileLdr)
 
423
        return 0;
 
424
 
 
425
    return Open(fileLdr, filename, pos, data);
 
426
}
 
427
 
 
428
cbEditor* EditorManager::Open(LoaderBase* fileLdr, const wxString& filename, int pos,ProjectFile* data)
 
429
{
 
430
    bool can_updateui = !GetActiveEditor() || !Manager::Get()->GetProjectManager()->IsLoading();
 
431
    wxFileName fn(filename);
 
432
    NormalizePath(fn, wxEmptyString);
 
433
    wxString fname = UnixFilename(fn.GetFullPath());
 
434
    //  Manager::Get()->GetLogManager()->DebugLog("Trying to open '%s'", fname.c_str());
 
435
    if (!wxFileExists(fname))
 
436
        return NULL;
 
437
    //  Manager::Get()->GetLogManager()->DebugLog("File exists '%s'", fname.c_str());
 
438
 
 
439
    // disallow application shutdown while opening files
 
440
    // WARNING: remember to set it to true, when exiting this function!!!
 
441
    s_CanShutdown = false;
 
442
 
 
443
    EditorBase* eb = IsOpen(fname);
 
444
    cbEditor* ed = 0;
 
445
    if (eb)
 
446
    {
 
447
        if (eb->IsBuiltinEditor())
 
448
            ed = (cbEditor*)eb;
 
449
        else
 
450
            return 0; // is open but not a builtin editor
 
451
    }
 
452
 
 
453
    if (!ed)
 
454
    {
 
455
        ed = new cbEditor(m_pNotebook, fileLdr, fname, m_Theme);
 
456
        if (ed->IsOK())
 
457
            AddEditorBase(ed);
 
458
        else
 
459
        {
 
460
            ed->Destroy();
 
461
            ed = NULL;
 
462
        }
 
463
    }
 
464
 
 
465
    if(can_updateui)
 
466
    {
 
467
        if (ed)
 
468
        {
 
469
            SetActiveEditor(ed);
 
470
            ed->GetControl()->SetFocus();
 
471
        }
 
472
    }
 
473
 
 
474
    // check for ProjectFile
 
475
    if (ed && !ed->GetProjectFile())
 
476
    {
 
477
        // First checks if we're already being passed a ProjectFile
 
478
        // as a parameter
 
479
        if(data)
 
480
        {
 
481
            Manager::Get()->GetLogManager()->DebugLog(_T("project data set for ") + data->file.GetFullPath());
 
482
        }
 
483
        else
 
484
        {
 
485
            ProjectsArray* projects = Manager::Get()->GetProjectManager()->GetProjects();
 
486
            for (unsigned int i = 0; i < projects->GetCount(); ++i)
 
487
            {
 
488
                cbProject* prj = projects->Item(i);
 
489
                ProjectFile* pf = prj->GetFileByFilename(ed->GetFilename(), false);
 
490
                if (pf)
 
491
                {
 
492
                    Manager::Get()->GetLogManager()->DebugLog(_T("found ") + pf->file.GetFullPath());
 
493
                    data = pf;
 
494
                    break;
 
495
                }
 
496
            }
 
497
        }
 
498
        if(data)
 
499
            ed->SetProjectFile(data,true);
 
500
    }
 
501
 
 
502
    // we 're done
 
503
    s_CanShutdown = true;
 
504
 
 
505
    return ed;
 
506
}
 
507
 
 
508
EditorBase* EditorManager::GetActiveEditor()
 
509
{
 
510
    return InternalGetEditorBase(m_pNotebook->GetSelection());
 
511
}
 
512
 
 
513
void EditorManager::ActivateNext()
 
514
{
 
515
    m_pNotebook->AdvanceSelection(true);
 
516
}
 
517
 
 
518
void EditorManager::ActivatePrevious()
 
519
{
 
520
    m_pNotebook->AdvanceSelection(false);
 
521
}
 
522
 
 
523
void EditorManager::SetActiveEditor(EditorBase* ed)
 
524
{
 
525
    if (!ed)
 
526
        return;
 
527
    if (ed->IsBuiltinEditor())
 
528
        static_cast<cbEditor*>(ed)->GetControl()->SetFocus();
 
529
    int page = FindPageFromEditor(ed);
 
530
    if (page != -1)
 
531
    {
 
532
        m_pNotebook->SetSelection(page);
 
533
    }
 
534
}
 
535
 
 
536
cbEditor* EditorManager::New(const wxString& newFileName)
 
537
{
 
538
//    wxString old_title = Manager::Get()->GetAppWindow()->GetTitle(); // Fix for Bug #1389450
 
539
    // create a dummy file
 
540
    if (!newFileName.IsEmpty() && !wxFileExists(newFileName) && wxDirExists(wxPathOnly(newFileName)))
 
541
    {
 
542
        wxFile f(newFileName, wxFile::write);
 
543
        if (!f.IsOpened())
 
544
            return 0;
 
545
    }
 
546
    cbEditor* ed = new cbEditor(m_pNotebook, newFileName);
 
547
//    if ((newFileName.IsEmpty() && !ed->SaveAs()) || !ed->Save())
 
548
//    {
 
549
//        //DeletePage(ed->GetPageIndex());
 
550
//        ed->Destroy();
 
551
//        Manager::Get()->GetAppWindow()->SetTitle(old_title); // Though I can't reproduce the bug, this does no harm
 
552
//        return 0L;
 
553
//    }
 
554
 
 
555
    // add default text
 
556
    wxString key;
 
557
    key.Printf(_T("/default_code/set%d"), (int)FileTypeOf(ed->GetFilename()));
 
558
    wxString code = Manager::Get()->GetConfigManager(_T("editor"))->Read(key, wxEmptyString);
 
559
    ed->GetControl()->SetText(code);
 
560
 
 
561
    ed->SetColourSet(m_Theme);
 
562
    AddEditorBase(ed);
 
563
 
 
564
    ed->Show(true);
 
565
    SetActiveEditor(ed);
 
566
    CodeBlocksEvent evt(cbEVT_EDITOR_OPEN, -1, 0, ed);
 
567
    Manager::Get()->GetPluginManager()->NotifyPlugins(evt);
 
568
    return ed;
 
569
}
 
570
 
 
571
void EditorManager::AddCustomEditor(EditorBase* eb)
 
572
{
 
573
    AddEditorBase(eb);
 
574
}
 
575
 
 
576
void EditorManager::RemoveCustomEditor(EditorBase* eb)
 
577
{
 
578
    RemoveEditorBase(eb, false);
 
579
}
 
580
 
 
581
void EditorManager::AddEditorBase(EditorBase* eb)
 
582
{
 
583
    int page = FindPageFromEditor(eb);
 
584
    if (page == -1)
 
585
    {
 
586
        //        LOGSTREAM << wxString::Format(_T("AddEditorBase(): ed=%p, title=%s\n"), eb, eb ? eb->GetTitle().c_str() : _T(""));
 
587
        m_pNotebook->AddPage(eb, eb->GetTitle(), true);
 
588
    }
 
589
}
 
590
 
 
591
void EditorManager::RemoveEditorBase(EditorBase* eb, bool deleteObject)
 
592
{
 
593
    //    LOGSTREAM << wxString::Format(_T("RemoveEditorBase(): ed=%p, title=%s\n"), eb, eb ? eb->GetFilename().c_str() : _T(""));
 
594
    int page = FindPageFromEditor(eb);
 
595
   if (page != -1 && !Manager::isappShuttingDown())
 
596
        m_pNotebook->RemovePage(page, false);
 
597
 
 
598
    //    if (deleteObject)
 
599
    //        eb->Destroy();
 
600
}
 
601
 
 
602
bool EditorManager::UpdateProjectFiles(cbProject* project)
 
603
{
 
604
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
605
    {
 
606
        cbEditor* ed = InternalGetBuiltinEditor(i);
 
607
        if (!ed)
 
608
            continue;
 
609
        ProjectFile* pf = ed->GetProjectFile();
 
610
        if (!pf)
 
611
            continue;
 
612
        if (pf->GetParentProject() != project)
 
613
            continue;
 
614
        pf->editorTopLine = ed->GetControl()->GetFirstVisibleLine();
 
615
        pf->editorPos = ed->GetControl()->GetCurrentPos();
 
616
        pf->editorTabPos = i + 1;
 
617
        pf->editorOpen = true;
 
618
    }
 
619
    return true;
 
620
}
 
621
 
 
622
bool EditorManager::CloseAll(bool dontsave)
 
623
{
 
624
    //return CloseAllExcept(0L,dontsave);
 
625
    return CloseAllExcept(GetEditor(_("Start here")), dontsave);
 
626
}
 
627
 
 
628
bool EditorManager::QueryCloseAll()
 
629
{
 
630
    for (int i = m_pNotebook->GetPageCount() - 1; i >= 0; --i)
 
631
    {
 
632
        EditorBase* eb = InternalGetEditorBase(i);
 
633
        if(eb && !QueryClose(eb))
 
634
            return false; // aborted
 
635
    }
 
636
    return true;
 
637
}
 
638
 
 
639
bool EditorManager::CloseAllExcept(EditorBase* editor,bool dontsave)
 
640
{
 
641
    if(!dontsave)
 
642
    {
 
643
        for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
644
        {
 
645
            EditorBase* eb = InternalGetEditorBase(i);
 
646
            if(eb && eb != editor && !QueryClose(eb))
 
647
                return false; // aborted
 
648
        }
 
649
    }
 
650
 
 
651
    m_pNotebook->Freeze();
 
652
    int count = m_pNotebook->GetPageCount();
 
653
    for (int i = m_pNotebook->GetPageCount() - 1; i >= 0; --i)
 
654
    {
 
655
        EditorBase* eb = InternalGetEditorBase(i);
 
656
        if (eb && eb != editor && Close(eb, true))
 
657
            --count;
 
658
    }
 
659
    m_pNotebook->Thaw();
 
660
    return count == (editor ? 1 : 0);
 
661
}
 
662
 
 
663
bool EditorManager::CloseActive(bool dontsave)
 
664
{
 
665
    return Close(GetActiveEditor(),dontsave);
 
666
}
 
667
 
 
668
bool EditorManager::QueryClose(EditorBase *ed)
 
669
{
 
670
    if(!ed)
 
671
        return true;
 
672
    if (ed->GetModified())
 
673
    {
 
674
        // TODO (mandrav#1#): Move this in EditorBase
 
675
        wxString msg;
 
676
        msg.Printf(_("File %s is modified...\nDo you want to save the changes?"), ed->GetFilename().c_str());
 
677
        switch (cbMessageBox(msg, _("Save file"), wxICON_QUESTION | wxYES_NO | wxCANCEL))
 
678
        {
 
679
        case wxID_YES:
 
680
            if (!ed->Save())
 
681
                return false;
 
682
            break;
 
683
        case wxID_NO:
 
684
            break;
 
685
        case wxID_CANCEL:
 
686
            return false;
 
687
        }
 
688
        ed->SetModified(false);
 
689
    }
 
690
    else
 
691
    {
 
692
        return ed->QueryClose();
 
693
    }
 
694
    return true;
 
695
}
 
696
 
 
697
int EditorManager::FindPageFromEditor(EditorBase* eb)
 
698
{
 
699
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
700
    {
 
701
        if (m_pNotebook->GetPage(i) == eb)
 
702
            return i;
 
703
    }
 
704
    return -1;
 
705
}
 
706
 
 
707
bool EditorManager::Close(const wxString& filename,bool dontsave)
 
708
{
 
709
    return Close(IsOpen(filename),dontsave);
 
710
}
 
711
 
 
712
bool EditorManager::Close(EditorBase* editor,bool dontsave)
 
713
{
 
714
    if (editor)
 
715
    {
 
716
        int idx = FindPageFromEditor(editor);
 
717
        if (idx != -1)
 
718
        {
 
719
            if(!dontsave)
 
720
                if(!QueryClose(editor))
 
721
                    return false;
 
722
            wxString filename = editor->GetFilename();
 
723
            //            LOGSTREAM << wxString::Format(_T("Close(): ed=%p, title=%s\n"), editor, editor ? editor->GetTitle().c_str() : _T(""));
 
724
            m_pNotebook->DeletePage(idx, true);
 
725
        }
 
726
    }
 
727
    return true;
 
728
}
 
729
 
 
730
bool EditorManager::Close(int index,bool dontsave)
 
731
{
 
732
    EditorBase* ed = InternalGetEditorBase(index);
 
733
    if (ed)
 
734
        return Close(ed,dontsave);
 
735
    return false;
 
736
}
 
737
 
 
738
bool EditorManager::Save(const wxString& filename)
 
739
{
 
740
    //    cbEditor* ed = GetBuiltinEditor(IsOpen(filename));
 
741
    EditorBase* ed = IsOpen(filename);
 
742
    if (ed)
 
743
    {
 
744
        wxString oldname = ed->GetFilename();
 
745
        if (!ed->Save())
 
746
            return false;
 
747
        return true;
 
748
    }
 
749
    return true;
 
750
}
 
751
 
 
752
bool EditorManager::Save(int index)
 
753
{
 
754
    EditorBase* ed = InternalGetEditorBase(index);
 
755
    if (ed)
 
756
    {
 
757
        wxString oldname = ed->GetFilename();
 
758
        if (!ed->Save())
 
759
            return false;
 
760
        return true;
 
761
    }
 
762
    return false;
 
763
}
 
764
 
 
765
bool EditorManager::SaveActive()
 
766
{
 
767
    EditorBase* ed = GetActiveEditor();
 
768
    if (ed)
 
769
    {
 
770
        wxString oldname = ed->GetFilename();
 
771
        if (!ed->Save())
 
772
            return false;
 
773
        return true;
 
774
    }
 
775
    return true;
 
776
}
 
777
 
 
778
bool EditorManager::SaveAs(int index)
 
779
{
 
780
    cbEditor* ed = GetBuiltinEditor(GetEditor(index));
 
781
    if(!ed)
 
782
        return false;
 
783
    return ed->SaveAs();
 
784
}
 
785
 
 
786
bool EditorManager::SaveActiveAs()
 
787
{
 
788
    cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
 
789
    if (ed)
 
790
    {
 
791
        return ed->SaveAs();
 
792
    }
 
793
    return true;
 
794
}
 
795
 
 
796
bool EditorManager::SaveAll()
 
797
{
 
798
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
799
    {
 
800
        EditorBase* ed = InternalGetEditorBase(i);
 
801
        if (ed && ed->GetModified() && !ed->Save())
 
802
        {
 
803
            wxString msg;
 
804
            msg.Printf(_("File %s could not be saved..."), ed->GetFilename().c_str());
 
805
            cbMessageBox(msg, _("Error saving file"), wxICON_ERROR);
 
806
        }
 
807
    }
 
808
 
 
809
    return true;
 
810
}
 
811
 
 
812
void EditorManager::Print(PrintScope ps, PrintColourMode pcm, bool line_numbers)
 
813
{
 
814
    switch (ps)
 
815
    {
 
816
    case psAllOpenEditors:
 
817
        {
 
818
            for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
819
            {
 
820
                cbEditor* ed = InternalGetBuiltinEditor(i);
 
821
                if (ed)
 
822
                    ed->Print(false, pcm, line_numbers);
 
823
            }
 
824
            break;
 
825
        }
 
826
    default:
 
827
        {
 
828
            cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
 
829
            if (ed)
 
830
                ed->Print(ps == psSelection, pcm, line_numbers);
 
831
            break;
 
832
        }
 
833
    }
 
834
}
 
835
 
 
836
void EditorManager::CheckForExternallyModifiedFiles()
 
837
{
 
838
    if(m_isCheckingForExternallyModifiedFiles) // for some reason, a mutex locker does not work???
 
839
        return;
 
840
    m_isCheckingForExternallyModifiedFiles = true;
 
841
 
 
842
    bool reloadAll = false; // flag to stop bugging the user
 
843
    wxArrayString failedFiles; // list of files failed to reload
 
844
    for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
845
    {
 
846
        cbEditor* ed = InternalGetBuiltinEditor(i);
 
847
        bool b_modified = false;
 
848
 
 
849
        // no builtin editor or new file not yet saved
 
850
        if (!ed || !ed->IsOK())
 
851
            continue;
 
852
        //File was deleted?
 
853
        if (!wxFileExists(ed->GetFilename()))
 
854
        {
 
855
            if(ed->GetModified()) // Already set the flag
 
856
                continue;
 
857
            wxString msg;
 
858
            msg.Printf(_("%s has been deleted, or is no longer available.\n"
 
859
                         "Do you wish to keep the file open?\n"
 
860
                         "Yes to keep the file, No to close it."), ed->GetFilename().c_str());
 
861
            if (cbMessageBox(msg, _("File changed!"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
 
862
                ed->SetModified(true);
 
863
            else
 
864
            {
 
865
                ed->Close();
 
866
                ProjectFile* pf = ed->GetProjectFile();
 
867
                if (pf)
 
868
                    pf->SetFileState(fvsMissing);
 
869
            }
 
870
            continue;
 
871
        }
 
872
 
 
873
        ProjectFile* pf = ed->GetProjectFile();
 
874
        wxFileName fname(ed->GetFilename());
 
875
        wxDateTime last = fname.GetModificationTime();
 
876
 
 
877
        //File changed from RO -> RW?
 
878
        if (ed->GetControl()->GetReadOnly() &&
 
879
                wxFile::Access(ed->GetFilename().c_str(), wxFile::write))
 
880
        {
 
881
            b_modified = false;
 
882
            ed->GetControl()->SetReadOnly(false);
 
883
            if (pf)
 
884
                pf->SetFileState(fvsNormal);
 
885
        }
 
886
        //File changed from RW -> RO?
 
887
        if (!ed->GetControl()->GetReadOnly() &&
 
888
                !wxFile::Access(ed->GetFilename().c_str(), wxFile::write))
 
889
        {
 
890
            b_modified = false;
 
891
            ed->GetControl()->SetReadOnly(true);
 
892
            if (pf)
 
893
                pf->SetFileState(fvsReadOnly);
 
894
        }
 
895
        //File content changed?
 
896
        if (last.IsLaterThan(ed->GetLastModificationTime()))
 
897
            b_modified = true;
 
898
 
 
899
        if (b_modified)
 
900
        {
 
901
            // modified; ask to reload
 
902
            int ret = -1;
 
903
            if (!reloadAll)
 
904
            {
 
905
                wxString msg;
 
906
                msg.Printf(_("File %s is modified outside the IDE...\nDo you want to reload it (you will lose any unsaved work)?"),
 
907
                           ed->GetFilename().c_str());
 
908
                ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow(), false, msg);
 
909
                dlg.SetTitle(_("Reload file?"));
 
910
                PlaceWindow(&dlg);
 
911
                ret = dlg.ShowModal();
 
912
                reloadAll = ret == crAll;
 
913
            }
 
914
            if (reloadAll || ret == crYes)
 
915
            {
 
916
                if (!ed->Reload())
 
917
                    failedFiles.Add(ed->GetFilename());
 
918
            }
 
919
            else if (ret == crCancel)
 
920
                break;
 
921
            else if (ret == crNo)
 
922
                ed->Touch();
 
923
        }
 
924
    }
 
925
 
 
926
    // this will emmit a EVT_EDITOR_ACTIVATED event, which in turn will notify
 
927
    // the app to update the currently active file's info
 
928
    // (we 're interested in updating read-write state)
 
929
    SetActiveEditor(GetActiveEditor());
 
930
 
 
931
    if (failedFiles.GetCount())
 
932
    {
 
933
        wxString msg;
 
934
        msg.Printf(_("Could not reload all files:\n\n%s"), GetStringFromArray(failedFiles, _T("\n")).c_str());
 
935
        cbMessageBox(msg, _("Error"), wxICON_ERROR);
 
936
    }
 
937
    m_isCheckingForExternallyModifiedFiles = false;
 
938
} // end of CheckForExternallyModifiedFiles
 
939
 
 
940
bool EditorManager::SwapActiveHeaderSource()
 
941
{
 
942
    cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
 
943
    if (!ed)
 
944
        return false;
 
945
 
 
946
    FileType ft = FileTypeOf(ed->GetFilename());
 
947
    if (ft != ftHeader && ft != ftSource)
 
948
        return 0L;
 
949
 
 
950
    // create a list of search dirs
 
951
    wxArrayString dirs;
 
952
 
 
953
    cbProject* project = 0;
 
954
 
 
955
    // if the file in question belongs to a different open project,
 
956
    // then use that project instead.
 
957
    // this fixes locating the file's pair in a workspace when the active file
 
958
    // does not belong to the active project.
 
959
    ProjectFile* opf = ed->GetProjectFile();
 
960
    if (opf)
 
961
        project = opf->GetParentProject();
 
962
 
 
963
    // if we didn't get a valid project, try the active one
 
964
    if (!project)
 
965
        project = Manager::Get()->GetProjectManager()->GetActiveProject();
 
966
 
 
967
    // get project's include dirs
 
968
    if (project)
 
969
    {
 
970
        dirs = project->GetIncludeDirs();
 
971
 
 
972
        // first add all paths that contain project files
 
973
        for (int i = 0; i < project->GetFilesCount(); ++i)
 
974
        {
 
975
            ProjectFile* pf = project->GetFile(i);
 
976
            if (pf)
 
977
            {
 
978
                wxString dir = pf->file.GetPath(wxPATH_GET_VOLUME);
 
979
                if (dirs.Index(dir) == wxNOT_FOUND)
 
980
                    dirs.Add(dir);
 
981
            }
 
982
        }
 
983
 
 
984
        // get targets include dirs
 
985
        for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
 
986
        {
 
987
            ProjectBuildTarget* target = project->GetBuildTarget(i);
 
988
            if (target)
 
989
            {
 
990
                for (unsigned int ti = 0; ti < target->GetIncludeDirs().GetCount(); ++ti)
 
991
                {
 
992
                    wxString dir = target->GetIncludeDirs()[ti];
 
993
                    if (dirs.Index(dir) == wxNOT_FOUND)
 
994
                        dirs.Add(dir);
 
995
                }
 
996
            }
 
997
        }
 
998
    }
 
999
 
 
1000
    wxFileName fname;
 
1001
    wxFileName fn(ed->GetFilename());
 
1002
    dirs.Insert(fn.GetPath(wxPATH_GET_VOLUME), 0); // add file's dir
 
1003
 
 
1004
    for (unsigned int i = 0; i < dirs.GetCount(); ++i)
 
1005
    {
 
1006
        fname.Assign(dirs[i] + wxFileName::GetPathSeparator() + fn.GetFullName());
 
1007
        if (!fname.IsAbsolute() && project)
 
1008
        {
 
1009
            fname.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, project->GetBasePath());
 
1010
        }
 
1011
        //Manager::Get()->GetLogManager()->DebugLog("Looking for '%s'", fname.GetFullPath().c_str());
 
1012
        if (ft == ftHeader)
 
1013
        {
 
1014
            fname.SetExt(FileFilters::C_EXT);
 
1015
            if (fname.FileExists())
 
1016
                break;
 
1017
            fname.SetExt(FileFilters::CC_EXT);
 
1018
            if (fname.FileExists())
 
1019
                break;
 
1020
            fname.SetExt(FileFilters::CPP_EXT);
 
1021
            if (fname.FileExists())
 
1022
                break;
 
1023
            fname.SetExt(FileFilters::CXX_EXT);
 
1024
            if (fname.FileExists())
 
1025
                break;
 
1026
        }
 
1027
        else if (ft == ftSource)
 
1028
        {
 
1029
            fname.SetExt(FileFilters::H_EXT);
 
1030
            if (fname.FileExists())
 
1031
                break;
 
1032
            fname.SetExt(FileFilters::HH_EXT);
 
1033
            if (fname.FileExists())
 
1034
                break;
 
1035
            fname.SetExt(FileFilters::HPP_EXT);
 
1036
            if (fname.FileExists())
 
1037
                break;
 
1038
            fname.SetExt(FileFilters::HXX_EXT);
 
1039
            if (fname.FileExists())
 
1040
                break;
 
1041
        }
 
1042
    }
 
1043
 
 
1044
    if (fname.FileExists())
 
1045
    {
 
1046
        //Manager::Get()->GetLogManager()->DebugLog("ed=%s, pair=%s", ed->GetFilename().c_str(), pair.c_str());
 
1047
        cbEditor* newEd = Open(fname.GetFullPath());
 
1048
        //if (newEd)
 
1049
        //    newEd->SetProjectFile(ed->GetProjectFile());
 
1050
        return newEd;
 
1051
    }
 
1052
 
 
1053
    // We couldn't find the file, maybe it does not exist. Ask the user if we
 
1054
    // should create it:
 
1055
    if (cbMessageBox(_("The file does not exist. Do you want to create it?"),
 
1056
                _("Error"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
 
1057
    {
 
1058
        cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
 
1059
        if (project)
 
1060
            wxSetWorkingDirectory(project->GetBasePath());
 
1061
 
 
1062
        // Create a suggestion for the new file name:
 
1063
        if (ft == ftHeader)
 
1064
            fn.SetExt(FileFilters::CPP_EXT);
 
1065
        else if (ft == ftSource)
 
1066
            fn.SetExt(FileFilters::H_EXT);
 
1067
        // else? Well, if the filename is not changed we could possibly
 
1068
        // overwrite an existing file with our suggestion.
 
1069
 
 
1070
        cbEditor* newEd = New(fn.GetFullPath());
 
1071
        if (cbMessageBox(_("Do you want to add this new file in the active project?"),
 
1072
                    _("Add file to project"),
 
1073
                    wxYES_NO | wxICON_QUESTION) == wxID_YES)
 
1074
        {
 
1075
            wxArrayInt targets;
 
1076
            if (Manager::Get()->GetProjectManager()->AddFileToProject(newEd->GetFilename(), project, targets) != 0)
 
1077
            {
 
1078
                ProjectFile* pf = project->GetFileByFilename(newEd->GetFilename(), false);
 
1079
                newEd->SetProjectFile(pf);
 
1080
                Manager::Get()->GetProjectManager()->RebuildTree();
 
1081
            }
 
1082
        }
 
1083
        // verify that the open files are still in sync
 
1084
        // the new file might have overwritten an existing one)
 
1085
        Manager::Get()->GetEditorManager()->CheckForExternallyModifiedFiles();
 
1086
    }
 
1087
    return 0L;
 
1088
}
 
1089
 
 
1090
int EditorManager::ShowFindDialog(bool replace, bool explicitly_find_in_files)
 
1091
{
 
1092
    wxString phraseAtCursor;
 
1093
    bool hasSelection = false;
 
1094
    cbStyledTextCtrl* control = 0;
 
1095
 
 
1096
    cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
 
1097
    if (ed)
 
1098
    {
 
1099
        control = ed->GetControl();
 
1100
 
 
1101
        hasSelection = control->GetSelectionStart() != control->GetSelectionEnd();
 
1102
        int wordStart = control->WordStartPosition(control->GetCurrentPos(), true);
 
1103
        int wordEnd = control->WordEndPosition(control->GetCurrentPos(), true);
 
1104
        wxString wordAtCursor = control->GetTextRange(wordStart, wordEnd);
 
1105
        phraseAtCursor = control->GetSelectedText();
 
1106
        // if selected text is part of a single line, don't suggest "search in selection"
 
1107
        if (control->LineFromPosition(control->GetSelectionStart())
 
1108
            == control->LineFromPosition(control->GetSelectionEnd()))
 
1109
            hasSelection = false;
 
1110
 
 
1111
        if ( phraseAtCursor.IsEmpty())
 
1112
            phraseAtCursor = wordAtCursor;
 
1113
 
 
1114
        int selstartline = control->LineFromPosition(control->GetSelectionStart());
 
1115
        int selendline   = control->LineFromPosition(control->GetSelectionEnd());
 
1116
        // the selection of several lines is not proposed as search pattern
 
1117
        if ( selstartline != selendline )
 
1118
            phraseAtCursor = wxEmptyString;
 
1119
 
 
1120
    }
 
1121
 
 
1122
    FindReplaceBase* dlg;
 
1123
    if (!replace)
 
1124
        dlg = new FindDlg(Manager::Get()->GetAppWindow(), phraseAtCursor, hasSelection, !ed, explicitly_find_in_files);
 
1125
    else
 
1126
        dlg = new ReplaceDlg(Manager::Get()->GetAppWindow(), phraseAtCursor, hasSelection, !ed, explicitly_find_in_files);
 
1127
 
 
1128
    PlaceWindow(dlg);
 
1129
    if (dlg->ShowModal() == wxID_CANCEL)
 
1130
    {
 
1131
        dlg->Destroy();
 
1132
        return -2;
 
1133
    }
 
1134
 
 
1135
    // Don't look for empty strings:
 
1136
    if (dlg->GetFindString().empty())
 
1137
    {
 
1138
        dlg->Destroy();
 
1139
        cbMessageBox(_("Can't look for an empty search criterion!"), _("Error"), wxOK | wxICON_EXCLAMATION, Manager::Get()->GetAppWindow());
 
1140
        return -2;
 
1141
    }
 
1142
 
 
1143
    if (!m_LastFindReplaceData)
 
1144
        m_LastFindReplaceData = new cbFindReplaceData;
 
1145
 
 
1146
    m_LastFindReplaceData->start = 0;
 
1147
    m_LastFindReplaceData->end = 0;
 
1148
    m_LastFindReplaceData->findText = dlg->GetFindString();
 
1149
    m_LastFindReplaceData->replaceText = dlg->GetReplaceString();
 
1150
 
 
1151
    m_LastFindReplaceData->findInFiles = dlg->IsFindInFiles();
 
1152
    if(!m_LastFindReplaceData->findInFiles)
 
1153
    {
 
1154
        //AutoWrapSearch does not exist in FindInFiles dialog
 
1155
        m_LastFindReplaceData->autoWrapSearch = dlg->GetAutoWrapSearch();
 
1156
 
 
1157
        //FindUsesSelectedText does not exist in Replace dialogs
 
1158
        if (!replace)
 
1159
            m_LastFindReplaceData->findUsesSelectedText = dlg->GetFindUsesSelectedText();
 
1160
    }
 
1161
    m_LastFindReplaceData->delOldSearches = dlg->GetDeleteOldSearches();
 
1162
    m_LastFindReplaceData->matchWord = dlg->GetMatchWord();
 
1163
    m_LastFindReplaceData->startWord = dlg->GetStartWord();
 
1164
    m_LastFindReplaceData->matchCase = dlg->GetMatchCase();
 
1165
    m_LastFindReplaceData->regEx = dlg->GetRegEx();
 
1166
    m_LastFindReplaceData->directionDown = dlg->GetDirection() == 1;
 
1167
    m_LastFindReplaceData->originEntireScope = dlg->GetOrigin() == 1;
 
1168
    m_LastFindReplaceData->scope = dlg->GetScope();
 
1169
    m_LastFindReplaceData->searchPath = dlg->GetSearchPath();
 
1170
    m_LastFindReplaceData->searchMask = dlg->GetSearchMask();
 
1171
    m_LastFindReplaceData->recursiveSearch = dlg->GetRecursive();
 
1172
    m_LastFindReplaceData->hiddenSearch = dlg->GetHidden();
 
1173
    m_LastFindReplaceData->initialreplacing = false;
 
1174
    m_LastFindReplaceData->NewSearch = true;
 
1175
    if(control)
 
1176
    {   // if editor : store the selection start/end
 
1177
        // only use this in case of !findInFiles and scope==1 (search in selection)
 
1178
        m_LastFindReplaceData->SearchInSelectionStart = control->GetSelectionStart();
 
1179
        m_LastFindReplaceData->SearchInSelectionEnd = control->GetSelectionEnd();
 
1180
    }
 
1181
    dlg->Destroy();
 
1182
 
 
1183
    int ReturnValue = 0;
 
1184
    if (!replace)
 
1185
    {
 
1186
        if (m_LastFindReplaceData->findInFiles)
 
1187
            ReturnValue = FindInFiles(m_LastFindReplaceData);
 
1188
        else
 
1189
            ReturnValue = Find(control, m_LastFindReplaceData);
 
1190
    }
 
1191
    else
 
1192
    {
 
1193
        m_LastFindReplaceData->initialreplacing = true;
 
1194
 
 
1195
        if (m_LastFindReplaceData->findInFiles)
 
1196
            ReturnValue = ReplaceInFiles(m_LastFindReplaceData);
 
1197
        else
 
1198
            ReturnValue = Replace(control, m_LastFindReplaceData);
 
1199
    }
 
1200
    m_LastFindReplaceData->NewSearch = false; // we have searched, so no longer new search
 
1201
 
 
1202
    //Default back to find or replace in Editor
 
1203
    if(m_LastFindReplaceData->findInFiles)
 
1204
    {
 
1205
        m_LastFindReplaceData->findInFiles = false;
 
1206
    }
 
1207
    return ReturnValue;
 
1208
} // end of ShowFindDialog
 
1209
 
 
1210
void EditorManager::CalculateFindReplaceStartEnd(cbStyledTextCtrl* control, cbFindReplaceData* data, bool replace)
 
1211
{
 
1212
    if (!control || !data)
 
1213
        return;
 
1214
 
 
1215
    if (!data->findInFiles)   // Find in current Editor
 
1216
    {
 
1217
        int ssta = control->GetSelectionStart();
 
1218
        int send = control->GetSelectionEnd();
 
1219
        int cpos = control->GetCurrentPos();
 
1220
        int clen = control->GetLength();
 
1221
 
 
1222
        // when the user initially had a selection, but then changed the scope
 
1223
        // to entire scope, the values of ssta and send will have a bad influence in
 
1224
        // the following calculations, therefor check for the scenario
 
1225
        // and set the ssta en send to cpos (in the case there would be no selection
 
1226
        // that's the value they have [no selection : ssta=send=cpos])
 
1227
        // only do this when it's a new search (when the search is continued (F3/Shift-F3)
 
1228
        // there can be a selection, the last found match)
 
1229
        if(data->scope== 0 && data->NewSearch && (ssta != cpos || send != cpos))
 
1230
        {
 
1231
            ssta = cpos;
 
1232
            send = cpos;
 
1233
        }
 
1234
 
 
1235
 
 
1236
 
 
1237
        data->start = 0;
 
1238
        data->end   = clen;
 
1239
 
 
1240
        if (!data->originEntireScope || !data->NewSearch)   // from pos or next/prev search
 
1241
        {
 
1242
            if (!data->directionDown)   // up
 
1243
                // initial replacing mode - include selection end : normal mode - skip until selection start
 
1244
                data->start = (data->initialreplacing)? std::max(send, cpos) : std::min(ssta, cpos);
 
1245
            else                      // down
 
1246
                // initial replacing mode - include selection start : normal mode - skip until selection end
 
1247
                data->start = (data->initialreplacing)? std::min(ssta, cpos) : std::max(send, cpos);
 
1248
        }
 
1249
        else                            // entire scope
 
1250
        {
 
1251
            if (!data->directionDown)   // up
 
1252
                data->start = clen;
 
1253
        }
 
1254
 
 
1255
        if (!data->directionDown)       // up
 
1256
            data->end = 0;
 
1257
 
 
1258
        // selected text, if user has deslected since last, then change scope
 
1259
        if (data->scope == 1 &&
 
1260
            control->GetSelectionStart()==control->GetSelectionEnd())
 
1261
                data->scope = 0;
 
1262
 
 
1263
        if (data->scope == 1) // selected text
 
1264
        {
 
1265
            if(data->NewSearch)
 
1266
            {
 
1267
                if (!data->directionDown)   // up
 
1268
                {
 
1269
                    data->start = std::max(ssta, send);
 
1270
                    data->end   = std::min(ssta, send);
 
1271
                }
 
1272
                else // down
 
1273
                {
 
1274
                    data->start = std::min(ssta, send);
 
1275
                    data->end   = std::max(ssta, send);
 
1276
                }
 
1277
            }
 
1278
            else
 
1279
            {   // this is the result of a next/previous search
 
1280
                // rebase depending on the cursor position
 
1281
                ssta = data->SearchInSelectionStart;
 
1282
                send = data->SearchInSelectionEnd;
 
1283
                if(cpos < ssta || cpos > send)
 
1284
                {   // regular reset (this also provide some sort of wrap around) (other editors also did it like that)
 
1285
                    data->start = ssta;
 
1286
                    data->end = send;
 
1287
                }
 
1288
                else
 
1289
                {
 
1290
                    data->start = cpos;
 
1291
                    data->end = (data->directionDown)?send:ssta;
 
1292
                }
 
1293
            }
 
1294
        }
 
1295
    }
 
1296
    else        // FindInFiles
 
1297
    {           // searching direction down, entire scope
 
1298
        //Replace needs the entire scope, while find can wrap around.
 
1299
        data->start = ( replace ? 0 : control->GetCurrentPos() );
 
1300
        data->end   = control->GetLength();
 
1301
    }
 
1302
} // end of CalculateFindReplaceStartEnd
 
1303
 
 
1304
int EditorManager::Replace(cbStyledTextCtrl* control, cbFindReplaceData* data)
 
1305
{
 
1306
    if (!control || !data)
 
1307
        return -1;
 
1308
 
 
1309
    bool AdvRegex=false;
 
1310
    int replacecount=0;
 
1311
    int foundcount=0;
 
1312
    int flags = 0;
 
1313
    CalculateFindReplaceStartEnd(control, data);
 
1314
 
 
1315
    if (data->matchWord)
 
1316
        flags |= wxSCI_FIND_WHOLEWORD;
 
1317
    if (data->startWord)
 
1318
        flags |= wxSCI_FIND_WORDSTART;
 
1319
    if (data->matchCase)
 
1320
        flags |= wxSCI_FIND_MATCHCASE;
 
1321
    if (data->regEx)
 
1322
    {
 
1323
        flags |= wxSCI_FIND_REGEXP;
 
1324
        if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
 
1325
            flags |= wxSCI_FIND_POSIX;
 
1326
        #ifdef wxHAS_REGEX_ADVANCED
 
1327
        AdvRegex=Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
 
1328
        #endif
 
1329
    }
 
1330
 
 
1331
    wxRegEx re;
 
1332
    #ifdef wxHAS_REGEX_ADVANCED
 
1333
    if(AdvRegex)
 
1334
    {
 
1335
        if(data->matchCase)
 
1336
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE);
 
1337
        else
 
1338
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE|wxRE_ICASE);
 
1339
    }
 
1340
    #endif
 
1341
 
 
1342
    control->BeginUndoAction();
 
1343
    int pos = -1;
 
1344
    bool replace = false;
 
1345
    bool confirm = true;
 
1346
    bool stop = false;
 
1347
    wxPoint LastDlgPosition;
 
1348
    bool HaveLastDlgPosition = false;
 
1349
    bool wrapAround = false;
 
1350
    int  data_start_initial = data->start;
 
1351
 
 
1352
    while (!stop)
 
1353
    {
 
1354
        int lengthFound = 0;
 
1355
        if(!AdvRegex)
 
1356
            pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
 
1357
        else
 
1358
        {
 
1359
            wxString text=control->GetTextRange(data->start, data->end);
 
1360
            if(re.Matches(text))
 
1361
            {
 
1362
                size_t start,len;
 
1363
                re.GetMatch(&start,&len,0);
 
1364
                pos=start+data->start;
 
1365
                lengthFound=len;
 
1366
                if(start==0&&len==0) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
 
1367
                {
 
1368
                    text=text.Mid(1);
 
1369
                    if(re.Matches(text))
 
1370
                    {
 
1371
                        size_t start,len;
 
1372
                        re.GetMatch(&start,&len,0);
 
1373
                        pos=start+data->start+1;
 
1374
                        lengthFound=len;
 
1375
                    } else
 
1376
                        pos=-1;
 
1377
                }
 
1378
            } else
 
1379
                pos=-1;
 
1380
        }
 
1381
        if (pos != -1 && data->start!=data->end)
 
1382
        {
 
1383
            control->GotoPos(pos);
 
1384
            control->EnsureVisible(control->LineFromPosition(pos));
 
1385
            control->SetSelection(pos, pos + lengthFound);
 
1386
            data->start = pos;
 
1387
            data->initialreplacing = false;  // special treatment only necessary the first time
 
1388
        }
 
1389
        else if (!wrapAround)
 
1390
        {
 
1391
            if ( (data->scope == 0) &&      // scope = global text
 
1392
                    ((data->directionDown && data_start_initial != 0) ||
 
1393
                     (!data->directionDown && data_start_initial != control->GetLength())))
 
1394
            {
 
1395
                wxString msg;
 
1396
                if (data->directionDown)
 
1397
                    msg = _("Text not found.\nSearch from the start of the document?");
 
1398
                else
 
1399
                    msg = _("Text not found.\nSearch from the end of the document?");
 
1400
 
 
1401
                bool auto_wrap_around = data->autoWrapSearch;
 
1402
                if (auto_wrap_around)
 
1403
                    wxBell();
 
1404
                if (auto_wrap_around || cbMessageBox(msg, _("Result"), wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
 
1405
                {
 
1406
                    data->end = data_start_initial;
 
1407
                    data->start = (data->directionDown)? 0 : control->GetLength();
 
1408
                    wrapAround = true; // signal the wrap-around
 
1409
                    continue;
 
1410
                }
 
1411
                else
 
1412
                    break;  // done - user doesn't want to wrap around
 
1413
            }
 
1414
            else
 
1415
                break; // done - we're replacing in a selection of text
 
1416
        }
 
1417
        else
 
1418
            break; // done - already wrapped around once
 
1419
 
 
1420
        foundcount++;
 
1421
 
 
1422
        if (confirm)
 
1423
        {
 
1424
            ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow());
 
1425
            // dlg.CalcPosition(control);
 
1426
            // TODO (thomas#1#): Check whether the existing code actually works with twin view
 
1427
            // else, we need something like:
 
1428
            // PlaceWindow(&dlg, pdlRelative);
 
1429
 
 
1430
            // NOTE (Tiwag#1#): dlg.CalcPosition doesn't work for me with dual monitor setup,
 
1431
            //     workaround : remember last dialog position, user can position
 
1432
            //                  it outside of text where he wants
 
1433
            // Move dialog to last position if already available,
 
1434
            // else place it according to environments settings
 
1435
            if ( HaveLastDlgPosition )
 
1436
                dlg.Move(LastDlgPosition);
 
1437
            else
 
1438
                dlg.CalcPosition(control);
 
1439
 
 
1440
            int ans = dlg.ShowModal();
 
1441
            LastDlgPosition = dlg.GetPosition();
 
1442
            HaveLastDlgPosition = true;
 
1443
            switch (ans)
 
1444
            {
 
1445
            case crYes:
 
1446
                replace = true;
 
1447
                break;
 
1448
            case crNo:
 
1449
                replace = false;
 
1450
                break;
 
1451
            case crAll:
 
1452
                replace = true;
 
1453
                confirm = false;
 
1454
                break;
 
1455
            case crCancel:
 
1456
                stop = true;
 
1457
                break;
 
1458
            }
 
1459
        }
 
1460
 
 
1461
        if (!stop)
 
1462
        {
 
1463
            if (replace)
 
1464
            {
 
1465
                int lengthReplace = data->replaceText.Length();
 
1466
                replacecount++;
 
1467
                if (data->regEx)
 
1468
                {
 
1469
                    // set target same as selection
 
1470
                    control->SetTargetStart(control->GetSelectionStart());
 
1471
                    control->SetTargetEnd(control->GetSelectionEnd());
 
1472
                    if(AdvRegex)
 
1473
                    {
 
1474
                        wxString text=control->GetSelectedText();
 
1475
                        re.Replace(&text,data->replaceText,1);
 
1476
                        lengthReplace=text.Len();
 
1477
                        control->ReplaceSelection(text);
 
1478
                    } else
 
1479
                    {
 
1480
                        // replace with regEx support
 
1481
                        lengthReplace = control->ReplaceTargetRE(data->replaceText);
 
1482
                    }
 
1483
                    // reset target
 
1484
                    control->SetTargetStart(0);
 
1485
                    control->SetTargetEnd(0);
 
1486
                }
 
1487
                else
 
1488
                    control->ReplaceSelection(data->replaceText);
 
1489
                if (data->directionDown)
 
1490
                {
 
1491
                    data->start += lengthReplace;
 
1492
                }
 
1493
                // adjust end pos by adding the length difference between find and replace strings
 
1494
                int diff = lengthReplace - lengthFound;
 
1495
                if (data->directionDown)
 
1496
                {
 
1497
                    data->end += diff;
 
1498
                }
 
1499
                else
 
1500
                {
 
1501
                    if(data->end < diff)
 
1502
                    {
 
1503
                       data->end = 0;
 
1504
                    }
 
1505
                    else
 
1506
                    {
 
1507
                       data->end -= diff;
 
1508
                    }
 
1509
                }
 
1510
            }
 
1511
            else
 
1512
                if (data->directionDown)
 
1513
                    data->start += lengthFound;
 
1514
                else
 
1515
                    data->start -= lengthFound;
 
1516
 
 
1517
        }
 
1518
    }
 
1519
    control->EndUndoAction();
 
1520
    wxString msg;
 
1521
    if (foundcount == 0)
 
1522
                msg = _T("No matches found for \"") + data->findText + _T("\"");
 
1523
    else if (replacecount == 0 && foundcount == 1)
 
1524
                msg = _T("One match found but not replaced");
 
1525
    else
 
1526
                msg.Printf(_("Replaced %i of %i matches"), replacecount, foundcount);
 
1527
    cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
 
1528
    control->SetSCIFocus(true);
 
1529
 
 
1530
    return pos;
 
1531
}
 
1532
 
 
1533
int EditorManager::ReplaceInFiles(cbFindReplaceData* data)
 
1534
{
 
1535
    if (!data) return 0;
 
1536
    if (data->findText.IsEmpty()) return 0;
 
1537
 
 
1538
    // let's make a list of all the files to search in
 
1539
    wxArrayString filesList;
 
1540
 
 
1541
    if (data->scope == 0) // find in project files
 
1542
    {
 
1543
        // fill the search list with all the project files
 
1544
        cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
 
1545
        if (!prj)
 
1546
            return 0;
 
1547
 
 
1548
        wxString fullpath = _T("");
 
1549
        for (int i = 0; i < prj->GetFilesCount(); ++i)
 
1550
        {
 
1551
            ProjectFile* pf = prj->GetFile(i);
 
1552
            if (pf)
 
1553
            {
 
1554
                fullpath = pf->file.GetFullPath();
 
1555
                if (filesList.Index(fullpath) == -1) // avoid adding duplicates
 
1556
                {
 
1557
                    if(wxFileExists(fullpath))  // Does the file exist?
 
1558
                        filesList.Add(fullpath);
 
1559
                }
 
1560
            }
 
1561
        }
 
1562
    }
 
1563
    else if (data->scope == 1) // find in open files
 
1564
    {
 
1565
        // fill the search list with the open files
 
1566
        for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
1567
        {
 
1568
            cbEditor* ed = InternalGetBuiltinEditor(i);
 
1569
            if (ed)
 
1570
                filesList.Add(ed->GetFilename());
 
1571
        }
 
1572
    }
 
1573
    else if (data->scope == 2) // find in workspace
 
1574
    {
 
1575
        // loop over all the projects in the workspace (they are contained in the ProjectManager)
 
1576
        const ProjectsArray* pProjects = Manager::Get()->GetProjectManager()->GetProjects();
 
1577
        if(pProjects)
 
1578
        {
 
1579
            int count = pProjects->GetCount();
 
1580
            for (int idxProject = 0; idxProject < count; ++idxProject)
 
1581
            {
 
1582
                cbProject* pProject = pProjects->Item(idxProject);
 
1583
                if(pProject)
 
1584
                {
 
1585
                    wxString fullpath = _T("");
 
1586
                    for (int idxFile = 0; idxFile < pProject->GetFilesCount(); ++idxFile)
 
1587
                    {
 
1588
                        ProjectFile* pf = pProject->GetFile(idxFile);
 
1589
                        if (pf)
 
1590
                        {
 
1591
                            fullpath = pf->file.GetFullPath();
 
1592
                            if (filesList.Index(fullpath) == -1) // avoid adding duplicates
 
1593
                            {
 
1594
                                if(wxFileExists(fullpath))  // Does the file exist?
 
1595
                                    filesList.Add(fullpath);
 
1596
                            }
 
1597
                        }
 
1598
                    } // end for : idx : idxFile
 
1599
                }
 
1600
            } // end for : idx : idxProject
 
1601
        }
 
1602
    }
 
1603
 
 
1604
    // if the list is empty, leave
 
1605
    int filesCount = filesList.GetCount();
 
1606
    if (filesCount == 0)
 
1607
    {
 
1608
        cbMessageBox(_("No files to search in!"), _("Error"), wxICON_WARNING);
 
1609
        return 0;
 
1610
    }
 
1611
 
 
1612
    bool AdvRegex=false;
 
1613
    int flags = 0;
 
1614
    if (data->matchWord)
 
1615
        flags |= wxSCI_FIND_WHOLEWORD;
 
1616
    if (data->startWord)
 
1617
        flags |= wxSCI_FIND_WORDSTART;
 
1618
    if (data->matchCase)
 
1619
        flags |= wxSCI_FIND_MATCHCASE;
 
1620
    if (data->regEx)
 
1621
    {
 
1622
        flags |= wxSCI_FIND_REGEXP;
 
1623
        if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
 
1624
            flags |= wxSCI_FIND_POSIX;
 
1625
        #ifdef wxHAS_REGEX_ADVANCED
 
1626
        AdvRegex=Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
 
1627
        #endif
 
1628
    }
 
1629
 
 
1630
    wxRegEx re;
 
1631
    #ifdef wxHAS_REGEX_ADVANCED
 
1632
    if(AdvRegex)
 
1633
    {
 
1634
        if(data->matchCase)
 
1635
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE);
 
1636
        else
 
1637
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE|wxRE_ICASE);
 
1638
    }
 
1639
    #endif
 
1640
 
 
1641
 
 
1642
    bool replace = false;
 
1643
    bool confirm = true;
 
1644
    bool stop = false;
 
1645
    bool wholeFile = false;
 
1646
    bool all = false;
 
1647
    int pos = -1;
 
1648
 
 
1649
    wxPoint LastDlgPosition;
 
1650
    bool HaveLastDlgPosition = false;
 
1651
 
 
1652
    wxProgressDialog* progress = 0;
 
1653
    wxString fileContents;
 
1654
    wxString enc_name = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/default_encoding"), wxLocale::GetSystemEncodingName());
 
1655
    wxFontEncoding def_encoding = wxFontMapper::GetEncodingFromName(enc_name);
 
1656
 
 
1657
    // keep a copy of the find struct
 
1658
    cbFindReplaceData dataCopy = *data;
 
1659
 
 
1660
    for (int i = 0; i<filesCount && !stop; ++i)
 
1661
    {
 
1662
        cbEditor *ed = NULL;
 
1663
        cbStyledTextCtrl *control = NULL;
 
1664
        bool fileWasNotOpen = false;
 
1665
 
 
1666
        if (progress)
 
1667
        {
 
1668
            if (!progress->Update(i))
 
1669
            {
 
1670
                if (cbMessageBox(_("Are you sure you want to stop replacing in files?"), _("Confirmation"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
 
1671
                    break;
 
1672
                else
 
1673
                    progress->Resume();
 
1674
            }
 
1675
        }
 
1676
 
 
1677
        //Check if this file is already open
 
1678
        EditorBase *eb = IsOpen(filesList[i]);
 
1679
        if (eb)
 
1680
        {
 
1681
            //File was already open
 
1682
            fileWasNotOpen = false;
 
1683
 
 
1684
            ed = GetBuiltinEditor(eb);
 
1685
            if (ed) control = ed->GetControl();
 
1686
        }
 
1687
 
 
1688
        //If it's still NULL, open a new editor
 
1689
        if (!control)
 
1690
        {
 
1691
            wxFile file(filesList[i]);
 
1692
            if (!file.IsOpened())
 
1693
                continue;
 
1694
            fileContents = cbReadFileContents(file, def_encoding);
 
1695
            if (fileContents.Find(data->findText) == -1)
 
1696
                continue;
 
1697
 
 
1698
            //File was not open, i opened it.
 
1699
            fileWasNotOpen = true;
 
1700
 
 
1701
            ed = Open(filesList[i]);
 
1702
            if (ed) control = ed->GetControl();
 
1703
        }
 
1704
        //Still NULL?
 
1705
        if (!control || !ed)
 
1706
            continue;
 
1707
 
 
1708
        SetActiveEditor(ed);
 
1709
        control->BeginUndoAction(); //undo
 
1710
 
 
1711
        *data = dataCopy;
 
1712
        CalculateFindReplaceStartEnd(control, data, true);
 
1713
 
 
1714
        //reset bools
 
1715
        wholeFile = false;
 
1716
        if (!all) confirm = true;
 
1717
 
 
1718
        //Replace in this file
 
1719
        while(!stop || wholeFile)
 
1720
        {
 
1721
            int lengthFound = 0;
 
1722
            if(!AdvRegex)
 
1723
                pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
 
1724
            else
 
1725
            {
 
1726
                wxString text=control->GetTextRange(data->start, data->end);
 
1727
                if(re.Matches(text))
 
1728
                {
 
1729
                    size_t start,len;
 
1730
                    re.GetMatch(&start,&len,0);
 
1731
                    pos=start+data->start;
 
1732
                    lengthFound=len;
 
1733
                    if(start==0&&len==0) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
 
1734
                    {
 
1735
                        text=text.Mid(1);
 
1736
                        if(re.Matches(text))
 
1737
                        {
 
1738
                            size_t start,len;
 
1739
                            re.GetMatch(&start,&len,0);
 
1740
                            pos=start+data->start+1;
 
1741
                            lengthFound=len;
 
1742
                        } else
 
1743
                            pos=-1;
 
1744
                    }
 
1745
                } else
 
1746
                    pos=-1;
 
1747
            }
 
1748
 
 
1749
            if (pos == -1 || data->start==data->end)
 
1750
                break;
 
1751
 
 
1752
            if (confirm)
 
1753
            {
 
1754
                control->GotoPos(pos);
 
1755
                control->EnsureVisible(control->LineFromPosition(pos));
 
1756
            }
 
1757
            control->SetSelection(pos, pos + lengthFound);
 
1758
            data->start = pos;
 
1759
            data->initialreplacing = false;  // special treatment only necessary the first time
 
1760
 
 
1761
            if (confirm)
 
1762
            {
 
1763
                ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow(), true);
 
1764
                // dlg.CalcPosition(control);
 
1765
                // TODO (thomas#1#): Check whether the existing code actually works with twin view
 
1766
                // else, we need something like:
 
1767
                // PlaceWindow(&dlg, pdlRelative);
 
1768
 
 
1769
                // NOTE (Tiwag#1#): dlg.CalcPosition doesn't work for me with dual monitor setup,
 
1770
                //     workaround : remember last dialog position, user can position
 
1771
                //                  it outside of text where he wants
 
1772
                // Move dialog to last position if already available,
 
1773
                // else place it according to environments settings
 
1774
                if ( HaveLastDlgPosition )
 
1775
                    dlg.Move(LastDlgPosition);
 
1776
                else
 
1777
                    dlg.CalcPosition(control);
 
1778
 
 
1779
                int ans = dlg.ShowModal();
 
1780
                LastDlgPosition = dlg.GetPosition();
 
1781
                HaveLastDlgPosition = true;
 
1782
                switch (ans)
 
1783
                {
 
1784
                    case crYes:
 
1785
                        replace = true;
 
1786
                        break;
 
1787
                    case crNo:
 
1788
                        replace = false;
 
1789
                        break;
 
1790
                    case crAllInFile:
 
1791
                        confirm = false;
 
1792
                        replace = true;
 
1793
                        wholeFile = true;
 
1794
                        break;
 
1795
                    case crSkipFile:
 
1796
                        confirm = false;
 
1797
                        replace = false;
 
1798
                        wholeFile = true;
 
1799
                        break;
 
1800
                    case crAll:
 
1801
                        replace = true;
 
1802
                        confirm = false;
 
1803
                        all = true;
 
1804
                        // let's create a progress dialog because it might take some time depending on the files count
 
1805
                        progress = new wxProgressDialog(_("Replace in files"),
 
1806
                                     _("Please wait while replacing in files..."),
 
1807
                                     filesCount,
 
1808
                                     Manager::Get()->GetAppWindow(),
 
1809
                                     wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
 
1810
                        PlaceWindow(progress);
 
1811
                        // now that we need no confirmation, freeze the app window
 
1812
                        Manager::Get()->GetAppWindow()->Freeze();
 
1813
                        break;
 
1814
                    case crCancel:
 
1815
                        stop = true;
 
1816
                        break;
 
1817
                }
 
1818
            }
 
1819
 
 
1820
            if (!stop)
 
1821
            {
 
1822
                if (replace)
 
1823
                {
 
1824
                    int lengthReplace = data->replaceText.Length();
 
1825
                    if (data->regEx)
 
1826
                    {
 
1827
                        // set target same as selection
 
1828
                        control->SetTargetStart(control->GetSelectionStart());
 
1829
                        control->SetTargetEnd(control->GetSelectionEnd());
 
1830
                        if(AdvRegex)
 
1831
                        {
 
1832
                            wxString text=control->GetSelectedText();
 
1833
                            re.Replace(&text,data->replaceText,1);
 
1834
                            lengthReplace=text.Len();
 
1835
                            control->ReplaceSelection(text);
 
1836
                        } else
 
1837
                        {
 
1838
                            // replace with regEx support
 
1839
                            lengthReplace = control->ReplaceTargetRE(data->replaceText);
 
1840
                        }
 
1841
                        // reset target
 
1842
                        control->SetTargetStart(0);
 
1843
                        control->SetTargetEnd(0);
 
1844
                    }
 
1845
                    else
 
1846
                        control->ReplaceSelection(data->replaceText);
 
1847
 
 
1848
                    data->start += lengthReplace;
 
1849
 
 
1850
                    // adjust end pos by adding the length difference
 
1851
                    //between find and replace strings
 
1852
                    int diff = lengthReplace - lengthFound;
 
1853
                    if (data->directionDown)
 
1854
                        data->end += diff;
 
1855
                    else
 
1856
                        data->end -= diff;
 
1857
                }
 
1858
                else
 
1859
                {
 
1860
                    if (data->directionDown)
 
1861
                        data->start += lengthFound;
 
1862
                    else
 
1863
                        data->start -= lengthFound;
 
1864
                }
 
1865
            }
 
1866
        }
 
1867
 
 
1868
        control->EndUndoAction(); // undo
 
1869
 
 
1870
        //If i opened the file and no replacement was made,
 
1871
        //close the editor
 
1872
        if (!ed->GetModified() && fileWasNotOpen)
 
1873
            Close(ed, true);
 
1874
    }
 
1875
 
 
1876
    // if we showed the progress, the app window is frozen; unfreeze it
 
1877
    if (progress)
 
1878
        Manager::Get()->GetAppWindow()->Thaw();
 
1879
 
 
1880
    delete progress;
 
1881
    return pos;
 
1882
}
 
1883
 
 
1884
int EditorManager::Find(cbStyledTextCtrl* control, cbFindReplaceData* data)
 
1885
{
 
1886
    if (!control || !data)
 
1887
        return -1;
 
1888
 
 
1889
    bool AdvRegex=false;
 
1890
    int flags = 0;
 
1891
    CalculateFindReplaceStartEnd(control, data);
 
1892
 
 
1893
    if (data->matchWord)
 
1894
        flags |= wxSCI_FIND_WHOLEWORD;
 
1895
    if (data->startWord)
 
1896
        flags |= wxSCI_FIND_WORDSTART;
 
1897
    if (data->matchCase)
 
1898
        flags |= wxSCI_FIND_MATCHCASE;
 
1899
    if (data->regEx)
 
1900
    {
 
1901
        flags |= wxSCI_FIND_REGEXP;
 
1902
        if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
 
1903
            flags |= wxSCI_FIND_POSIX;
 
1904
        #ifdef wxHAS_REGEX_ADVANCED
 
1905
        AdvRegex=Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
 
1906
        #endif
 
1907
    }
 
1908
 
 
1909
    wxRegEx re;
 
1910
    #ifdef wxHAS_REGEX_ADVANCED
 
1911
    if(AdvRegex)
 
1912
    {
 
1913
        if(data->matchCase)
 
1914
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE);
 
1915
        else
 
1916
            re.Compile(data->findText,wxRE_ADVANCED|wxRE_NEWLINE|wxRE_ICASE);
 
1917
    }
 
1918
    #endif
 
1919
 
 
1920
    int pos = -1;
 
1921
    // avoid infinite loop when wrapping search around, eventually crashing WinLogon O.O
 
1922
    bool wrapAround = false;
 
1923
    int StartPos = 0;
 
1924
    int EndPos = control->GetLength();
 
1925
    if(data->scope == 1)
 
1926
    {
 
1927
        StartPos = data->SearchInSelectionStart;
 
1928
        EndPos = data->SearchInSelectionEnd;
 
1929
    }
 
1930
    while (true) // loop while not found and user selects to start again from the top
 
1931
    {
 
1932
        int lengthFound = 0;
 
1933
        if(!AdvRegex)
 
1934
            pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
 
1935
        else
 
1936
        {
 
1937
            wxString text=control->GetTextRange(data->start, data->end);
 
1938
            if(re.Matches(text))
 
1939
            {
 
1940
                size_t start,len;
 
1941
                re.GetMatch(&start,&len,0);
 
1942
                pos=start+data->start;
 
1943
                lengthFound=len;
 
1944
                if(start==0&&len==0) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
 
1945
                {
 
1946
                    text=text.Mid(1);
 
1947
                    if(re.Matches(text))
 
1948
                    {
 
1949
                        size_t start,len;
 
1950
                        re.GetMatch(&start,&len,0);
 
1951
                        pos=start+data->start+1;
 
1952
                        lengthFound=len;
 
1953
                    } else
 
1954
                        pos=-1;
 
1955
                }
 
1956
            } else
 
1957
                pos=-1;
 
1958
        }
 
1959
        if (pos != -1 && data->start!=data->end)
 
1960
        {
 
1961
            int line = control->LineFromPosition(pos);
 
1962
                        int onScreen = control->LinesOnScreen() >> 1;
 
1963
                        int l1 = line - onScreen;
 
1964
                        int l2 = line + onScreen;
 
1965
                        for(int l=l1; l<=l2;l+=2)               // unfold visible lines on screen
 
1966
                                control->EnsureVisible(l);
 
1967
                        control->GotoLine(l1);                  // center selection on screen
 
1968
                        control->GotoLine(l2);
 
1969
            control->GotoLine(line);
 
1970
            control->SetSelection(pos, pos + lengthFound);
 
1971
            //            Manager::Get()->GetLogManager()->DebugLog("pos=%d, selLen=%d, length=%d", pos, data->end - data->start, lengthFound);
 
1972
            data->start = pos;
 
1973
            break; // done
 
1974
        }
 
1975
        else if (!wrapAround && !data->findInFiles) // for "find in files" we don't want to show messages
 
1976
        {
 
1977
            if (     (data->directionDown && data->start != StartPos) ||
 
1978
                     (!data->directionDown && data->start != EndPos)     )
 
1979
            {
 
1980
                wxString msg;
 
1981
                if(!data->scope == 1)
 
1982
                {
 
1983
                    if (data->directionDown)
 
1984
                        msg = _("Text not found.\nSearch from the start of the document?");
 
1985
                    else
 
1986
                        msg = _("Text not found.\nSearch from the end of the document?");
 
1987
                }
 
1988
                else
 
1989
                {
 
1990
                    if (data->directionDown)
 
1991
                        msg = _("Text not found.\nSearch from the start of the selection?");
 
1992
                    else
 
1993
                        msg = _("Text not found.\nSearch from the end of the selection?");
 
1994
                }
 
1995
 
 
1996
                bool auto_wrap_around = data->autoWrapSearch;
 
1997
                if (auto_wrap_around)
 
1998
                    wxBell();
 
1999
                if (auto_wrap_around || cbMessageBox(msg, _("Result"), wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
 
2000
                {
 
2001
                    wrapAround = true; // signal the wrap-around
 
2002
                    if(!data->scope == 1)
 
2003
                    {
 
2004
                        if (data->directionDown)
 
2005
                        {
 
2006
                            data->start = 0;
 
2007
                            data->end = control->GetLength();
 
2008
                        }
 
2009
                        else
 
2010
                        {
 
2011
                            data->start = control->GetLength();
 
2012
                            data->end = 0;
 
2013
                        }
 
2014
                    }
 
2015
                    else
 
2016
                    {
 
2017
                        if (data->directionDown)
 
2018
                        {
 
2019
                            data->start = data->SearchInSelectionStart;
 
2020
                            data->end = data->SearchInSelectionEnd;
 
2021
                        }
 
2022
                        else
 
2023
                        {
 
2024
                            data->start = data->SearchInSelectionEnd;
 
2025
                            data->end = data->SearchInSelectionStart;
 
2026
                        }
 
2027
                    }
 
2028
                }
 
2029
                else
 
2030
                    break; // done
 
2031
            }
 
2032
            else
 
2033
            {
 
2034
                wxString msg;
 
2035
                msg.Printf(_("Not found: %s"), data->findText.c_str());
 
2036
                cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
 
2037
                control->SetSCIFocus(true);
 
2038
                break; // done
 
2039
            }
 
2040
        }
 
2041
        else if (wrapAround)
 
2042
        {
 
2043
            wxString msg;
 
2044
            msg.Printf(_("Not found: %s"), data->findText.c_str());
 
2045
            cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
 
2046
            break; // done
 
2047
        }
 
2048
        else
 
2049
            break; // done
 
2050
    }
 
2051
    return pos;
 
2052
}
 
2053
 
 
2054
int EditorManager::FindInFiles(cbFindReplaceData* data)
 
2055
{
 
2056
    if (!data || data->findText.IsEmpty())
 
2057
        return 0;
 
2058
 
 
2059
    // clear old search results
 
2060
    if ( data->delOldSearches )
 
2061
    {
 
2062
        m_pSearchLog->Clear();
 
2063
    }
 
2064
    int oldcount = m_pSearchLog->GetItemsCount();
 
2065
 
 
2066
    // let's make a list of all the files to search in
 
2067
    wxArrayString filesList;
 
2068
 
 
2069
    if (data->scope == 0) // find in project files
 
2070
    {
 
2071
        // fill the search list with all the project files
 
2072
        cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
 
2073
        if (!prj)
 
2074
        {
 
2075
            cbMessageBox(_("No project to search in!"), _("Error"), wxICON_WARNING);
 
2076
            return 0;
 
2077
        }
 
2078
 
 
2079
        wxString fullpath = _T("");
 
2080
        for (int i = 0; i < prj->GetFilesCount(); ++i)
 
2081
        {
 
2082
            ProjectFile* pf = prj->GetFile(i);
 
2083
            if (pf)
 
2084
            {
 
2085
                fullpath = pf->file.GetFullPath();
 
2086
                if (filesList.Index(fullpath) == -1) // avoid adding duplicates
 
2087
                {
 
2088
                    if(wxFileExists(fullpath))  // Does the file exist?
 
2089
                        filesList.Add(fullpath);
 
2090
                }
 
2091
            }
 
2092
        }
 
2093
    }
 
2094
    else if (data->scope == 1) // find in open files
 
2095
    {
 
2096
        // fill the search list with the open files
 
2097
        for (int i = 0; i < m_pNotebook->GetPageCount(); ++i)
 
2098
        {
 
2099
            cbEditor* ed = InternalGetBuiltinEditor(i);
 
2100
            if (ed)
 
2101
                filesList.Add(ed->GetFilename());
 
2102
        }
 
2103
    }
 
2104
    else if (data->scope == 2) // find in custom search path and mask
 
2105
    {
 
2106
        // fill the search list with the files found under the search path
 
2107
        int flags = wxDIR_FILES |
 
2108
                    (data->recursiveSearch ? wxDIR_DIRS : 0) |
 
2109
                    (data->hiddenSearch ? wxDIR_HIDDEN : 0);
 
2110
        wxArrayString masks = GetArrayFromString(data->searchMask);
 
2111
        if (!masks.GetCount())
 
2112
            masks.Add(_T("*"));
 
2113
        unsigned int count = masks.GetCount();
 
2114
 
 
2115
        for (unsigned int i = 0; i < count; ++i)
 
2116
        {
 
2117
            // wxDir::GetAllFiles() does *not* clear the array, so it suits us just fine ;)
 
2118
            wxDir::GetAllFiles(data->searchPath, &filesList, masks[i], flags);
 
2119
        }
 
2120
    }
 
2121
    else if (data->scope == 3) // find in workspace
 
2122
    {
 
2123
        // loop over all the projects in the workspace (they are contained in the ProjectManager)
 
2124
        const ProjectsArray* pProjects = Manager::Get()->GetProjectManager()->GetProjects();
 
2125
        int count = 0;
 
2126
        if(pProjects)
 
2127
            count = pProjects->GetCount();
 
2128
        if(!count)
 
2129
        {
 
2130
            cbMessageBox(_("No workspace to search in!"), _("Error"), wxICON_WARNING);
 
2131
            return 0;
 
2132
        }
 
2133
        for (int idxProject = 0; idxProject < count; ++idxProject)
 
2134
        {
 
2135
            cbProject* pProject = pProjects->Item(idxProject);
 
2136
            if(pProject)
 
2137
            {
 
2138
                wxString fullpath = _T("");
 
2139
                for (int idxFile = 0; idxFile < pProject->GetFilesCount(); ++idxFile)
 
2140
                {
 
2141
                    ProjectFile* pf = pProject->GetFile(idxFile);
 
2142
                    if (pf)
 
2143
                    {
 
2144
                        fullpath = pf->file.GetFullPath();
 
2145
                        if (filesList.Index(fullpath) == -1) // avoid adding duplicates
 
2146
                        {
 
2147
                            if(wxFileExists(fullpath))  // Does the file exist?
 
2148
                                filesList.Add(fullpath);
 
2149
                        }
 
2150
                    }
 
2151
                } // end for : idx : idxFile
 
2152
            }
 
2153
        } // end for : idx : idxProject
 
2154
    }
 
2155
 
 
2156
    // if the list is empty, leave
 
2157
    if (filesList.GetCount() == 0)
 
2158
    {
 
2159
        cbMessageBox(_("No files to search in!"), _("Error"), wxICON_WARNING);
 
2160
        return 0;
 
2161
    }
 
2162
 
 
2163
    // now that list is filled, we'll search
 
2164
    // but first we'll create a hidden cbStyledTextCtrl to do the search for us ;)
 
2165
    cbStyledTextCtrl* control = new cbStyledTextCtrl(m_pNotebook, -1, wxDefaultPosition, wxSize(0, 0));
 
2166
    control->Show(false); //hidden
 
2167
 
 
2168
    // let's create a progress dialog because it might take some time depending on the files count
 
2169
    wxProgressDialog* progress = new wxProgressDialog(_("Find in files"),
 
2170
                                 _("Please wait while searching inside the files..."),
 
2171
                                 filesList.GetCount(),
 
2172
                                 Manager::Get()->GetAppWindow(),
 
2173
                                 wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
 
2174
 
 
2175
    PlaceWindow(progress);
 
2176
 
 
2177
    // keep a copy of the find struct
 
2178
    cbFindReplaceData localData = *data;
 
2179
 
 
2180
    if ( !data->delOldSearches )
 
2181
    {
 
2182
        LogSearch(_T("=========="), -1, _T("=== \"") + data->findText + _T("\" ==="));
 
2183
        oldcount++;
 
2184
    }
 
2185
 
 
2186
    int lastline = -1;
 
2187
    int count = 0;
 
2188
    for (size_t i = 0; i < filesList.GetCount(); ++i)
 
2189
    {
 
2190
        // update the progress bar
 
2191
        if (!progress->Update(i))
 
2192
            break; // user pressed "Cancel"
 
2193
 
 
2194
        // re-initialize the find struct for every file searched
 
2195
        *data = localData;
 
2196
 
 
2197
        // check if the file is already opened in built-in editor and do search in it
 
2198
        cbEditor* ed = IsBuiltinOpen(filesList[i]);
 
2199
        if (ed)
 
2200
            control->SetText(ed->GetControl()->GetText());
 
2201
        else if (!control->LoadFile(filesList[i])) // else load the file in the control
 
2202
        {
 
2203
            //            LOGSTREAM << _("Failed opening ") << filesList[i] << wxT('\n');
 
2204
            continue; // failed
 
2205
        }
 
2206
 
 
2207
        // now search for first occurence
 
2208
        if (Find(control, data) == -1)
 
2209
        {
 
2210
            lastline = -1;
 
2211
            continue;
 
2212
        }
 
2213
 
 
2214
        int line = control->LineFromPosition(control->GetSelectionStart());
 
2215
        lastline = line;
 
2216
 
 
2217
        // make the filename relative
 
2218
        wxString filename = filesList[i];
 
2219
        if (filename.StartsWith(data->searchPath))
 
2220
        {
 
2221
            wxFileName fname(filename);
 
2222
            fname.MakeRelativeTo(data->searchPath);
 
2223
            filename = fname.GetFullPath();
 
2224
        }
 
2225
 
 
2226
        // log it
 
2227
        LogSearch(filename, line + 1, control->GetLine(line));
 
2228
        ++count;
 
2229
 
 
2230
        // now loop finding the next occurence
 
2231
        while (FindNext(true, control, data) != -1)
 
2232
        {
 
2233
            // log it
 
2234
            line = control->LineFromPosition(control->GetSelectionStart());
 
2235
            if(line == lastline)  // avoid multiple hits on the same line (try search for "manager")
 
2236
                continue;
 
2237
 
 
2238
            lastline = line;
 
2239
            LogSearch(filename, line + 1, control->GetLine(line));
 
2240
            ++count;
 
2241
        }
 
2242
    }
 
2243
    delete control; // done with it
 
2244
    delete progress; // done here too
 
2245
 
 
2246
    if (count > 0)
 
2247
    {
 
2248
        static_cast<SearchResultsLog*>(m_pSearchLog)->SetBasePath(data->searchPath);
 
2249
        if (Manager::Get()->GetConfigManager(_T("message_manager"))->ReadBool(_T("/auto_show_search"), true))
 
2250
        {
 
2251
                CodeBlocksLogEvent evtSwitch(cbEVT_SWITCH_TO_LOG_WINDOW, m_pSearchLog);
 
2252
                CodeBlocksLogEvent evtShow(cbEVT_SHOW_LOG_MANAGER);
 
2253
 
 
2254
                        Manager::Get()->ProcessEvent(evtSwitch);
 
2255
                        Manager::Get()->ProcessEvent(evtShow);
 
2256
        }
 
2257
        static_cast<SearchResultsLog*>(m_pSearchLog)->FocusEntry(oldcount);
 
2258
    }
 
2259
    else
 
2260
    {
 
2261
        wxString msg;
 
2262
        if ( data->delOldSearches )
 
2263
        {
 
2264
            msg.Printf(_("Not found: %s"), data->findText.c_str());
 
2265
            cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
 
2266
            cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
 
2267
            if (ed)
 
2268
                ed->GetControl()->SetSCIFocus(true);
 
2269
        }
 
2270
        else
 
2271
        {
 
2272
            msg.Printf(_("not found in %d files"), filesList.GetCount());
 
2273
            LogSearch(_T(""), -1, msg );
 
2274
            static_cast<SearchResultsLog*>(m_pSearchLog)->FocusEntry(oldcount);
 
2275
        }
 
2276
    }
 
2277
 
 
2278
    return count;
 
2279
}
 
2280
 
 
2281
int EditorManager::FindNext(bool goingDown, cbStyledTextCtrl* control, cbFindReplaceData* data)
 
2282
{
 
2283
    if (!control)
 
2284
    {
 
2285
        cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
 
2286
        if (ed)
 
2287
            control = ed->GetControl();
 
2288
    }
 
2289
    if (!control)
 
2290
        return -1;
 
2291
 
 
2292
    if (!data)
 
2293
    {
 
2294
        data = m_LastFindReplaceData;
 
2295
        //FindNext/Previous called from Search menu (F3/Shift-F3)
 
2296
        if(data) data->findInFiles = false;
 
2297
    }
 
2298
 
 
2299
    if (!data)
 
2300
        return ShowFindDialog(false, false);
 
2301
 
 
2302
    if(!data->findInFiles)
 
2303
    {
 
2304
        wxString phraseAtCursor = control->GetSelectedText();
 
2305
 
 
2306
        if ( not data->findUsesSelectedText )
 
2307
        {   // The mandrav find behavior
 
2308
            // change findText to selected text (if any text is selected and no search text was set before)
 
2309
            if (!phraseAtCursor.IsEmpty() && data->findText.IsEmpty())
 
2310
                data->findText = phraseAtCursor;
 
2311
        }
 
2312
        else
 
2313
        {   // The tiwag find behavior
 
2314
            // change findText to selected text (if any text is selected)
 
2315
            if (!phraseAtCursor.IsEmpty())
 
2316
            {
 
2317
                data->findText = phraseAtCursor;
 
2318
                data->originEntireScope = false;  //search from cursor
 
2319
                data->scope = 0; // global ("selected text" is useful only from Find Dialog)
 
2320
            }
 
2321
        }
 
2322
    }
 
2323
 
 
2324
    data->directionDown = goingDown;
 
2325
    return Find(control, data);
 
2326
}
 
2327
 
 
2328
void EditorManager::OnGenericContextMenuHandler(wxCommandEvent& event)
 
2329
{
 
2330
    EditorBase* eb = GetActiveEditor();
 
2331
    cbEditor* ed = GetBuiltinEditor(eb);
 
2332
    int id = event.GetId();
 
2333
 
 
2334
    if (id == idNBTabSplitHorz && ed)
 
2335
        ed->Split(cbEditor::stHorizontal);
 
2336
    else if (id == idNBTabSplitVert && ed)
 
2337
        ed->Split(cbEditor::stVertical);
 
2338
    else if (id == idNBTabUnsplit && ed)
 
2339
        ed->Unsplit();
 
2340
}
 
2341
 
 
2342
void EditorManager::OnPageChanged(wxFlatNotebookEvent& event)
 
2343
{
 
2344
    EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(event.GetSelection()));
 
2345
    //    LOGSTREAM << wxString::Format(_T("OnPageChanged(): ed=%p, title=%s\n"), eb, eb ? eb->GetTitle().c_str() : _T(""));
 
2346
    CodeBlocksEvent evt(cbEVT_EDITOR_ACTIVATED, -1, 0, eb);
 
2347
    Manager::Get()->GetPluginManager()->NotifyPlugins(evt);
 
2348
 
 
2349
    // focus editor on next update event
 
2350
    m_pData->m_SetFocusFlag = true;
 
2351
 
 
2352
    event.Skip(); // allow others to process it too
 
2353
}
 
2354
 
 
2355
void EditorManager::OnPageChanging(wxFlatNotebookEvent& event)
 
2356
{
 
2357
    EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(event.GetOldSelection()));
 
2358
    //    LOGSTREAM << wxString::Format(_T("OnPageChanging(): ed=%p, title=%s\n"), eb, eb ? eb->GetTitle().c_str() : _T(""));
 
2359
    CodeBlocksEvent evt(cbEVT_EDITOR_DEACTIVATED, -1, 0, eb);
 
2360
    Manager::Get()->GetPluginManager()->NotifyPlugins(evt);
 
2361
 
 
2362
    event.Skip(); // allow others to process it too
 
2363
}
 
2364
 
 
2365
void EditorManager::OnPageClosing(wxFlatNotebookEvent& event)
 
2366
{
 
2367
    EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(event.GetSelection()));
 
2368
    //    LOGSTREAM << wxString::Format(_T("OnPageClosing(): ed=%p, title=%s\n"), eb, eb ? eb->GetTitle().c_str() : _T(""));
 
2369
    if (!QueryClose(eb))
 
2370
        event.Veto();
 
2371
    event.Skip(); // allow others to process it too
 
2372
}
 
2373
 
 
2374
void EditorManager::OnPageContextMenu(wxFlatNotebookEvent& event)
 
2375
{
 
2376
    if (event.GetSelection() == -1)
 
2377
        return;
 
2378
    wxMenu* pop = new wxMenu;
 
2379
    pop->Append(idNBTabClose, _("Close"));
 
2380
    if (GetEditorsCount() > 1)
 
2381
    {
 
2382
        pop->Append(idNBTabCloseAll, _("Close all"));
 
2383
        pop->Append(idNBTabCloseAllOthers, _("Close all others"));
 
2384
    }
 
2385
    pop->AppendSeparator();
 
2386
    pop->Append(idNBTabSave, _("Save"));
 
2387
    pop->Append(idNBTabSaveAll, _("Save all"));
 
2388
    pop->AppendSeparator();
 
2389
    pop->Append(idNBSwapHeaderSource, _("Swap header/source"));
 
2390
    pop->AppendSeparator();
 
2391
    pop->Append(idNBTabTop, _("Tabs at top"));
 
2392
    pop->Append(idNBTabBottom, _("Tabs at bottom"));
 
2393
 
 
2394
    cbEditor* ed = GetBuiltinEditor(event.GetSelection());
 
2395
    if (ed)
 
2396
    {
 
2397
        pop->AppendSeparator();
 
2398
        pop->Append(idNBProperties, _("Properties..."));
 
2399
 
 
2400
        wxMenu* splitMenu = new wxMenu;
 
2401
        splitMenu->Append(idNBTabSplitHorz, _("Horizontally"));
 
2402
        splitMenu->Append(idNBTabSplitVert, _("Vertically"));
 
2403
        splitMenu->AppendSeparator();
 
2404
        splitMenu->Append(idNBTabUnsplit, _("Unsplit"));
 
2405
        splitMenu->Enable(idNBTabSplitHorz, ed->GetSplitType() != cbEditor::stHorizontal);
 
2406
        splitMenu->Enable(idNBTabSplitVert, ed->GetSplitType() != cbEditor::stVertical);
 
2407
        splitMenu->Enable(idNBTabUnsplit, ed->GetSplitType() != cbEditor::stNoSplit);
 
2408
 
 
2409
        pop->AppendSeparator();
 
2410
        pop->Append(-1, _("Split view"), splitMenu);
 
2411
    }
 
2412
 
 
2413
    bool any_modified = false;
 
2414
 
 
2415
    for(int i = 0; i < GetEditorsCount(); ++i)
 
2416
    {
 
2417
        EditorBase* ed = GetEditor(i);
 
2418
        if (ed && ed->GetModified())
 
2419
        {
 
2420
            any_modified = true;
 
2421
            break;
 
2422
        }
 
2423
    }
 
2424
 
 
2425
    pop->Enable(idNBTabSave, GetEditor(event.GetSelection())->GetModified());
 
2426
    pop->Enable(idNBTabSaveAll, any_modified );
 
2427
 
 
2428
    m_pNotebook->PopupMenu(pop);
 
2429
    delete pop;
 
2430
}
 
2431
 
 
2432
void EditorManager::OnClose(wxCommandEvent& event)
 
2433
{
 
2434
    Manager::Get()->GetEditorManager()->Close(GetActiveEditor());
 
2435
}
 
2436
 
 
2437
void EditorManager::OnCloseAll(wxCommandEvent& event)
 
2438
{
 
2439
    Manager::Get()->GetEditorManager()->CloseAll();
 
2440
}
 
2441
 
 
2442
void EditorManager::OnCloseAllOthers(wxCommandEvent& event)
 
2443
{
 
2444
    Manager::Get()->GetEditorManager()->CloseAllExcept(GetActiveEditor());
 
2445
}
 
2446
 
 
2447
void EditorManager::OnSave(wxCommandEvent& event)
 
2448
{
 
2449
    Manager::Get()->GetEditorManager()->Save(m_pNotebook->GetSelection());
 
2450
}
 
2451
 
 
2452
void EditorManager::OnSaveAll(wxCommandEvent& event)
 
2453
{
 
2454
    Manager::Get()->GetEditorManager()->SaveAll();
 
2455
}
 
2456
 
 
2457
void EditorManager::OnSwapHeaderSource(wxCommandEvent& event)
 
2458
{
 
2459
    Manager::Get()->GetEditorManager()->SwapActiveHeaderSource();
 
2460
}
 
2461
 
 
2462
void EditorManager::OnTabPosition(wxCommandEvent& event)
 
2463
{
 
2464
    long style = m_pNotebook->GetWindowStyleFlag();
 
2465
    style &= ~wxFNB_BOTTOM;
 
2466
 
 
2467
    if (event.GetId() == idNBTabBottom)
 
2468
        style |= wxFNB_BOTTOM;
 
2469
    m_pNotebook->SetWindowStyleFlag(style);
 
2470
    // (style & wxFNB_BOTTOM) saves info only about the the tabs position
 
2471
    Manager::Get()->GetConfigManager(_T("app"))->Write(_T("/environment/editor_tabs_bottom"), (bool)(style & wxFNB_BOTTOM));
 
2472
}
 
2473
 
 
2474
void EditorManager::OnProperties(wxCommandEvent& event)
 
2475
{
 
2476
    cbEditor* ed = GetBuiltinActiveEditor();
 
2477
    ProjectFile* pf = 0;
 
2478
    if (ed)
 
2479
        pf = ed->GetProjectFile();
 
2480
    if (pf)
 
2481
        pf->ShowOptions(Manager::Get()->GetAppWindow());
 
2482
    else
 
2483
    {
 
2484
        ProjectFileOptionsDlg dlg(Manager::Get()->GetAppWindow(), GetActiveEditor()->GetFilename());
 
2485
        PlaceWindow(&dlg);
 
2486
        dlg.ShowModal();
 
2487
    }
 
2488
}
 
2489
 
 
2490
void EditorManager::OnAppDoneStartup(wxCommandEvent& event)
 
2491
{
 
2492
    event.Skip(); // allow others to process it too
 
2493
}
 
2494
 
 
2495
void EditorManager::OnAppStartShutdown(wxCommandEvent& event)
 
2496
{
 
2497
    event.Skip(); // allow others to process it too
 
2498
}
 
2499
 
 
2500
void EditorManager::OnCheckForModifiedFiles(wxCommandEvent& event)
 
2501
{
 
2502
    CheckForExternallyModifiedFiles();
 
2503
}
 
2504
 
 
2505
void EditorManager::HideNotebook()
 
2506
{
 
2507
    //    if(!this)
 
2508
    //        return;
 
2509
    //    if(m_pNotebook)
 
2510
    //        m_pNotebook->Hide();
 
2511
    //    m_pData->m_NeedsRefresh = false;
 
2512
    //    return;
 
2513
}
 
2514
 
 
2515
void EditorManager::ShowNotebook()
 
2516
{
 
2517
    //    if(!this)
 
2518
    //        return;
 
2519
    //    if(m_pNotebook)
 
2520
    //        m_pNotebook->Show();
 
2521
    //    m_pData->m_NeedsRefresh = true;
 
2522
    //    m_pData->InvalidateTree();
 
2523
    //    return;
 
2524
}
 
2525
 
 
2526
void EditorManager::OnUpdateUI(wxUpdateUIEvent& event)
 
2527
{
 
2528
    /* Don't process UpdateUI event when the app is closing.
 
2529
     * It may crash C::B */
 
2530
    if (!Manager::Get()->IsAppShuttingDown() && m_pData->m_SetFocusFlag)
 
2531
    {
 
2532
        cbEditor* ed = GetBuiltinActiveEditor();
 
2533
        if (ed)
 
2534
            ed->GetControl()->SetFocus();
 
2535
        m_pData->m_SetFocusFlag = false;
 
2536
    }
 
2537
 
 
2538
    // allow other UpdateUI handlers to process this event
 
2539
    // *very* important! don't forget it...
 
2540
    event.Skip();
 
2541
}
 
2542
 
 
2543
void EditorManager::SetZoom(int zoom)
 
2544
{
 
2545
    m_zoom = zoom;
 
2546
}
 
2547
 
 
2548
int EditorManager::GetZoom() const
 
2549
{
 
2550
    return m_zoom;
 
2551
}