~ubuntu-branches/ubuntu/maverick/poedit/maverick

« back to all changes in this revision

Viewing changes to src/edframe.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2008-09-16 19:47:00 UTC
  • mfrom: (0.2.9 upstream) (1.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20080916194700-ueyef0pgklk3u50k
Tags: 1.4.2-2
Adding debug package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  This file is part of Poedit (http://www.poedit.net)
3
3
 *
4
 
 *  Copyright (C) 1999-2007 Vaclav Slavik
 
4
 *  Copyright (C) 1999-2008 Vaclav Slavik
5
5
 *
6
6
 *  Permission is hereby granted, free of charge, to any person obtaining a
7
7
 *  copy of this software and associated documentation files (the "Software"),
21
21
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
22
 *  DEALINGS IN THE SOFTWARE. 
23
23
 *
24
 
 *  $Id: edframe.cpp 1254 2007-12-11 12:19:31Z vaclavslavik $
 
24
 *  $Id: edframe.cpp 1450 2008-08-12 16:53:24Z vaclavslavik $
25
25
 *
26
26
 *  Editor frame
27
27
 *
45
45
#include <wx/fontutil.h>
46
46
#include <wx/textfile.h>
47
47
#include <wx/wupdlock.h>
48
 
 
49
 
#if !wxCHECK_VERSION(2,8,0)
50
 
    #define wxFD_OPEN              wxOPEN
51
 
    #define wxFD_SAVE              wxSAVE
52
 
    #define wxFD_OVERWRITE_PROMPT  wxOVERWRITE_PROMPT
53
 
    #define wxFD_FILE_MUST_EXIST   wxFILE_MUST_EXIST
54
 
#endif
 
48
#include <wx/aboutdlg.h>
 
49
#include <wx/iconbndl.h>
 
50
#include <wx/clipbrd.h>
55
51
 
56
52
#ifdef USE_SPELLCHECKING
57
53
 
115
111
 
116
112
 
117
113
// I don't like this global flag, but all PoeditFrame instances must share it
118
 
bool gs_focusToText = false;
 
114
bool g_focusToText = false;
119
115
 
120
116
/*static*/ PoeditFrame *PoeditFrame::Find(const wxString& filename)
121
117
{
147
143
    }
148
144
    f->Show(true);
149
145
 
150
 
    if (gs_focusToText)
 
146
    if (g_focusToText)
151
147
        f->m_textTrans->SetFocus();
152
148
    else
153
149
        f->m_list->SetFocus();
160
156
class TextctrlHandler : public wxEvtHandler
161
157
{
162
158
    public:
163
 
        TextctrlHandler(PoeditFrame* frame) :
164
 
                 wxEvtHandler(), m_frame(frame), m_list(frame->m_list), m_sel(&(frame->m_sel)) {}
165
 
 
166
 
        void SetCatalog(Catalog* catalog) {m_catalog = catalog;}
 
159
        TextctrlHandler(PoeditFrame* frame) : m_list(frame->m_list) {}
167
160
 
168
161
    private:
169
162
        void OnKeyDown(wxKeyEvent& event)
170
163
        {
171
164
            int keyCode = event.GetKeyCode();
172
 
 
173
 
            if (!event.ControlDown())
 
165
            int modifiers = event.GetModifiers();
 
166
 
 
167
#if defined(__WXGTK__) && !wxCHECK_VERSION(2,8,9)
 
168
            // wxGTK < 2.8.9 had a bug in Meta key detection, see
 
169
            // bug #2006843 at http://tinyurl.com/56lsk2
 
170
            modifiers &= ~wxMOD_META;
 
171
#endif
 
172
 
 
173
            if ( modifiers != wxMOD_CMD ) // Cmd-* or Ctrl-*
174
174
            {
175
175
                event.Skip();
176
176
                return;
177
177
            }
178
178
 
 
179
            int sel = m_list->GetSelection();
 
180
 
179
181
            switch (keyCode)
180
182
            {
181
183
                case WXK_UP:
182
 
                    if ((*m_sel > 0))
 
184
                    if ((sel > 0))
183
185
                    {
184
186
#ifdef __WXMAC__
185
 
                        m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
 
187
                        m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
186
188
#endif
187
 
                        m_list->EnsureVisible(*m_sel - 1);
188
 
                        m_list->SetItemState(*m_sel - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
 
189
                        m_list->EnsureVisible(sel - 1);
 
190
                        m_list->SetItemState(sel - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
189
191
                    }
190
192
                    else
191
193
                        event.Skip();
192
194
                    break;
193
195
                case WXK_DOWN:
194
 
                    if ((*m_sel < m_list->GetItemCount() - 1))
 
196
                    if ((sel < m_list->GetItemCount() - 1))
195
197
                    {
196
198
#ifdef __WXMAC__
197
 
                        m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
 
199
                        m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
198
200
#endif
199
 
                        m_list->EnsureVisible(*m_sel + 1);
200
 
                        m_list->SetItemState(*m_sel + 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
 
201
                        m_list->EnsureVisible(sel + 1);
 
202
                        m_list->SetItemState(sel + 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
201
203
                    }
202
204
                    else
203
205
                        event.Skip();
205
207
                case WXK_PAGEUP:
206
208
                {
207
209
#ifdef __WXMAC__
208
 
                    m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
 
210
                    m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
209
211
#endif
210
 
                    int newy = *m_sel - 10;
 
212
                    int newy = sel - 10;
211
213
                    if (newy < 0) newy = 0;
212
214
                    m_list->EnsureVisible(newy);
213
215
                    m_list->SetItemState(newy, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
216
218
                case WXK_PAGEDOWN:
217
219
                {
218
220
#ifdef __WXMAC__
219
 
                    m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
 
221
                    m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
220
222
#endif
221
 
                    int newy = *m_sel + 10;
 
223
                    int newy = sel + 10;
222
224
                    if (newy >= m_list->GetItemCount())
223
225
                        newy = m_list->GetItemCount() - 1;
224
226
                    m_list->EnsureVisible(newy);
225
227
                    m_list->SetItemState(newy, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
226
228
                    break;
227
229
                }
 
230
 
 
231
#ifdef __WXMSW__
 
232
                // Text controls with wxTE_RICH2 style (richedit native
 
233
                // controls) don't generate WM_COPY, WM_PASTE and WM_CUT
 
234
                // messages that we need to capture (see below), so we have
 
235
                // to handle their respective keys ourselves:
 
236
                case 'C':
 
237
                {
 
238
                    wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
239
                    if ( txt )
 
240
                        txt->Copy();
 
241
                    else
 
242
                        event.Skip();
 
243
                    break;
 
244
                }
 
245
                case 'V':
 
246
                {
 
247
                    wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
248
                    if ( txt )
 
249
                        txt->Paste();
 
250
                    else
 
251
                        event.Skip();
 
252
                    break;
 
253
                }
 
254
                case 'X':
 
255
                {
 
256
                    wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
257
                    if ( txt )
 
258
                        txt->Cut();
 
259
                    else
 
260
                        event.Skip();
 
261
                    break;
 
262
                }
 
263
#endif
 
264
 
228
265
                default:
229
266
                    event.Skip();
230
267
            }
231
268
        }
232
269
 
 
270
#ifdef __WXMSW__
 
271
        // We use wxTE_RICH2 style, which allows for pasting rich-formatted
 
272
        // text into the control. We want to allow only plain text (all the
 
273
        // formatting done is Poedit's syntax highlighting), so we need to
 
274
        // override copy/cut/paste command.s Plus, the richedit control
 
275
        // (or wx's use of it) has a bug in it that causes it to copy wrong
 
276
        // data when copying from the same text control to itself after its
 
277
        // content was programatically changed:
 
278
        // https://sourceforge.net/tracker/index.php?func=detail&aid=1910234&group_id=27043&atid=389153
 
279
 
 
280
        bool DoCopy(wxTextCtrl *textctrl)
 
281
        {
 
282
            long from, to;
 
283
            textctrl->GetSelection(&from, &to);
 
284
            if ( from == to )
 
285
                return false;
 
286
 
 
287
            const wxString sel = textctrl->GetRange(from, to);
 
288
 
 
289
            wxClipboardLocker lock;
 
290
            wxCHECK_MSG( !!lock, false, _T("failed to lock clipboard") );
 
291
 
 
292
            wxClipboard::Get()->SetData(new wxTextDataObject(sel));
 
293
            return true;
 
294
        }
 
295
 
 
296
        void OnCopy(wxClipboardTextEvent& event)
 
297
        {
 
298
            wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
299
            wxCHECK_RET( textctrl, _T("wrong use of event handler") );
 
300
 
 
301
            DoCopy(textctrl);
 
302
        }
 
303
 
 
304
        void OnCut(wxClipboardTextEvent& event)
 
305
        {
 
306
            wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
307
            wxCHECK_RET( textctrl, _T("wrong use of event handler") );
 
308
 
 
309
            if ( !DoCopy(textctrl) )
 
310
                return;
 
311
 
 
312
            long from, to;
 
313
            textctrl->GetSelection(&from, &to);
 
314
            textctrl->Remove(from, to);
 
315
        }
 
316
 
 
317
        void OnPaste(wxClipboardTextEvent& event)
 
318
        {
 
319
            wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
 
320
            wxCHECK_RET( textctrl, _T("wrong use of event handler") );
 
321
 
 
322
            wxClipboardLocker lock;
 
323
            wxCHECK_RET( !!lock, _T("failed to lock clipboard") );
 
324
 
 
325
            wxTextDataObject d;
 
326
            wxClipboard::Get()->GetData(d);
 
327
 
 
328
            long from, to;
 
329
            textctrl->GetSelection(&from, &to);
 
330
            textctrl->Replace(from, to, d.GetText());
 
331
        }
 
332
#endif // __WXMSW__
 
333
 
233
334
        DECLARE_EVENT_TABLE()
234
335
 
235
 
        PoeditFrame    *m_frame;
236
336
        PoeditListCtrl *m_list;
237
 
        int            *m_sel;
238
 
        Catalog        *m_catalog;
239
337
 
240
338
        friend class ListHandler;
241
339
};
242
340
 
243
341
BEGIN_EVENT_TABLE(TextctrlHandler, wxEvtHandler)
244
 
   EVT_KEY_DOWN(TextctrlHandler::OnKeyDown)
245
 
END_EVENT_TABLE()
 
342
    EVT_KEY_DOWN(TextctrlHandler::OnKeyDown)
 
343
#ifdef __WXMSW__
 
344
    EVT_TEXT_COPY(-1, TextctrlHandler::OnCopy)
 
345
    EVT_TEXT_CUT(-1, TextctrlHandler::OnCut)
 
346
    EVT_TEXT_PASTE(-1, TextctrlHandler::OnPaste)
 
347
#endif
 
348
END_EVENT_TABLE()
 
349
 
 
350
 
 
351
class TransTextctrlHandler : public TextctrlHandler
 
352
{
 
353
    public:
 
354
        TransTextctrlHandler(PoeditFrame* frame)
 
355
            : TextctrlHandler(frame), m_frame(frame) {}
 
356
 
 
357
    private:
 
358
        void OnText(wxCommandEvent& event)
 
359
        {
 
360
            m_frame->UpdateFromTextCtrl();
 
361
            event.Skip();
 
362
        }
 
363
 
 
364
        PoeditFrame *m_frame;
 
365
 
 
366
        DECLARE_EVENT_TABLE()
 
367
};
 
368
 
 
369
BEGIN_EVENT_TABLE(TransTextctrlHandler, TextctrlHandler)
 
370
    EVT_TEXT(-1, TransTextctrlHandler::OnText)
 
371
END_EVENT_TABLE()
 
372
 
246
373
 
247
374
// special handling of events in listctrl
248
375
class ListHandler : public wxEvtHandler
253
380
 
254
381
    private:
255
382
        void OnSel(wxListEvent& event) { m_frame->OnListSel(event); }
256
 
        void OnDesel(wxListEvent& event) { m_frame->OnListDesel(event); }
257
383
        void OnActivated(wxListEvent& event) { m_frame->OnListActivated(event); }
258
384
        void OnRightClick(wxMouseEvent& event) { m_frame->OnListRightClick(event); }
259
385
        void OnFocus(wxFocusEvent& event) { m_frame->OnListFocus(event); }
266
392
 
267
393
BEGIN_EVENT_TABLE(ListHandler, wxEvtHandler)
268
394
   EVT_LIST_ITEM_SELECTED  (ID_LIST, ListHandler::OnSel)
269
 
   EVT_LIST_ITEM_DESELECTED(ID_LIST, ListHandler::OnDesel)
270
395
   EVT_LIST_ITEM_ACTIVATED (ID_LIST, ListHandler::OnActivated)
271
396
   EVT_RIGHT_DOWN          (          ListHandler::OnRightClick)
272
397
   EVT_SET_FOCUS           (          ListHandler::OnFocus)
358
483
    m_list(NULL),
359
484
    m_modified(false),
360
485
    m_hasObsoleteItems(false),
361
 
    m_sel(-1), //m_selItem(0),
362
 
    m_edittedTextFuzzyChanged(false)
 
486
    m_dontAutoclearFuzzyStatus(false)
363
487
{
364
488
    // make sure that the [ID_POEDIT_FIRST,ID_POEDIT_LAST] range of IDs is not
365
489
    // used for anything else:
382
506
    m_displayQuotes = (bool)cfg->Read(_T("display_quotes"), (long)false);
383
507
    m_displayLines = (bool)cfg->Read(_T("display_lines"), (long)false);
384
508
    m_displayCommentWin =
385
 
        (bool)cfg->Read(_T("display_comment_win"), (long)true);
 
509
        (bool)cfg->Read(_T("display_comment_win"), (long)false);
386
510
    m_displayAutoCommentsWin =
387
 
        (bool)cfg->Read(_T("display_auto_comments_win"), (long)true);
 
511
        (bool)cfg->Read(_T("display_auto_comments_win"), (long)false);
388
512
    m_commentWindowEditable =
389
513
        (bool)cfg->Read(_T("comment_window_editable"), (long)false);
390
 
    gs_focusToText = (bool)cfg->Read(_T("focus_to_text"), (long)false);
391
 
    gs_shadedList = (bool)cfg->Read(_T("shaded_list"), (long)true);
 
514
    g_focusToText = (bool)cfg->Read(_T("focus_to_text"), (long)false);
 
515
    g_shadedList = (bool)cfg->Read(_T("shaded_list"), (long)true);
392
516
 
393
517
#ifdef __UNIX__
394
 
    SetIcon(wxArtProvider::GetIcon(_T("poedit")));
 
518
    wxIconBundle appicons;
 
519
    appicons.AddIcon(wxArtProvider::GetIcon(_T("poedit"), wxART_FRAME_ICON, wxSize(16,16)));
 
520
    appicons.AddIcon(wxArtProvider::GetIcon(_T("poedit"), wxART_FRAME_ICON, wxSize(32,32)));
 
521
    appicons.AddIcon(wxArtProvider::GetIcon(_T("poedit"), wxART_FRAME_ICON, wxSize(48,48)));
 
522
    SetIcons(appicons);
395
523
#else
396
524
    SetIcon(wxICON(appicon));
397
525
#endif
427
555
    GetMenuBar()->Check(XRCID("menu_lines"), m_displayLines);
428
556
    GetMenuBar()->Check(XRCID("menu_comment_win"), m_displayCommentWin);
429
557
    GetMenuBar()->Check(XRCID("menu_auto_comments_win"), m_displayAutoCommentsWin);
430
 
    GetMenuBar()->Check(XRCID("menu_shaded"), gs_shadedList);
 
558
    GetMenuBar()->Check(XRCID("menu_shaded"), g_shadedList);
431
559
 
432
560
    CreateStatusBar(1, wxST_SIZEGRIP);
433
561
 
435
563
    //     it's not done correctly on wxMac:
436
564
    int posx = cfg->Read(_T("frame_x"), -1);
437
565
    int posy = cfg->Read(_T("frame_y"), -1);
438
 
    int width = cfg->Read(_T("frame_w"), 600);
439
 
    int height = cfg->Read(_T("frame_h"), 400);
 
566
    int width = cfg->Read(_T("frame_w"), 780);
 
567
    int height = cfg->Read(_T("frame_h"), 570);
440
568
 
441
569
    // NB: if this is the only Poedit frame opened, place it at remembered
442
570
    //     position, but don't do that if there already are other frames,
443
571
    //     because they would overlap and nobody could recognize that there are
444
572
    //     many of them
445
573
    if (ms_instances.GetCount() == 0)
446
 
        SetSize(posx, posy, width, height);
447
 
    else
448
 
        SetSize(-1, -1, width, height);
 
574
        Move(posx, posy);
 
575
    SetClientSize(width, height);
449
576
    if (cfg->Read(_T("frame_maximized"), long(0)))
450
577
        Maximize();
451
578
 
453
580
    m_splitter = new wxSplitterWindow(this, -1,
454
581
                                      wxDefaultPosition, wxDefaultSize,
455
582
                                      SPLITTER_FLAGS);
 
583
    // make only the upper part grow when resizing
 
584
    m_splitter->SetSashGravity(1.0);
456
585
 
457
586
    m_list = new PoeditListCtrl(m_splitter,
458
587
                                ID_LIST,
463
592
    m_bottomSplitter = new wxSplitterWindow(m_splitter, -1,
464
593
                                            wxDefaultPosition, wxDefaultSize,
465
594
                                            SPLITTER_FLAGS);
 
595
    // left part (translation) should grow, not comments one:
 
596
    m_bottomSplitter->SetSashGravity(1.0);
 
597
 
466
598
    m_bottomLeftPanel = new wxPanel(m_bottomSplitter);
467
599
    m_bottomRightPanel = new wxPanel(m_bottomSplitter);
468
600
 
470
602
    m_textAutoComments = new UnfocusableTextCtrl(m_bottomRightPanel,
471
603
                                ID_TEXTORIG, wxEmptyString,
472
604
                                wxDefaultPosition, wxDefaultSize,
473
 
                                wxTE_MULTILINE | wxTE_READONLY);
 
605
                                wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY);
474
606
    // This call will force the creation of the right kind of control
475
607
    // for the m_textComment member
476
608
    UpdateCommentWindowEditable();
480
612
    m_textOrig = new UnfocusableTextCtrl(m_bottomLeftPanel,
481
613
                                ID_TEXTORIG, wxEmptyString,
482
614
                                wxDefaultPosition, wxDefaultSize,
483
 
                                wxTE_MULTILINE | wxTE_READONLY);
 
615
                                wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY);
484
616
    m_textOrigPlural = new UnfocusableTextCtrl(m_bottomLeftPanel,
485
617
                                ID_TEXTORIGPLURAL, wxEmptyString,
486
618
                                wxDefaultPosition, wxDefaultSize,
487
 
                                wxTE_MULTILINE | wxTE_READONLY);
 
619
                                wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY);
488
620
 
489
621
    m_textTrans = new wxTextCtrl(m_bottomLeftPanel,
490
622
                                ID_TEXTTRANS, wxEmptyString,
491
623
                                wxDefaultPosition, wxDefaultSize,
492
 
                                wxTE_MULTILINE);
 
624
                                wxTE_MULTILINE | wxTE_RICH2);
493
625
 
494
626
    // in case of plurals form, this is the control for n=1:
495
627
    m_textTransSingularForm = NULL;
528
660
    m_bottomSplitter->Initialize(m_bottomLeftPanel);
529
661
 
530
662
    m_splitter->SetMinimumPaneSize(40);
531
 
    m_splitter->SplitHorizontally(m_list, m_bottomSplitter, cfg->Read(_T("splitter"), 240L));
 
663
    m_splitter->SplitHorizontally(m_list, m_bottomSplitter, cfg->Read(_T("splitter"), 330L));
532
664
 
533
665
    m_list->PushEventHandler(new ListHandler(this));
534
 
    m_textTrans->PushEventHandler(new TextctrlHandler(this));
 
666
    m_textTrans->PushEventHandler(new TransTextctrlHandler(this));
535
667
    m_textComment->PushEventHandler(new TextctrlHandler(this));
536
668
 
537
669
    ShowPluralFormUI(false);
557
689
 
558
690
    ms_instances.DeleteObject(this);
559
691
 
 
692
    m_list->PopEventHandler(true/*delete*/);
560
693
    m_textTrans->PopEventHandler(true/*delete*/);
561
 
    m_list->PopEventHandler(true/*delete*/);
 
694
    for (size_t i = 0; i < m_textTransPlural.size(); i++)
 
695
        m_textTransPlural[i]->PopEventHandler(true/*delete*/);
562
696
 
563
697
    wxConfigBase *cfg = wxConfig::Get();
564
698
    cfg->SetPath(_T("/"));
568
702
        if (!IsMaximized())
569
703
        {
570
704
            wxPoint pos = GetPosition();
571
 
            wxSize sz = GetSize();
 
705
            wxSize sz = GetClientSize();
572
706
 
573
707
            cfg->Write(_T("frame_w"), (long)sz.x);
574
708
            cfg->Write(_T("frame_h"), (long)sz.y);
589
723
    cfg->Write(_T("display_lines"), m_displayLines);
590
724
    cfg->Write(_T("display_comment_win"), m_displayCommentWin);
591
725
    cfg->Write(_T("display_auto_comments_win"), m_displayAutoCommentsWin);
592
 
    cfg->Write(_T("shaded_list"), gs_shadedList);
 
726
    cfg->Write(_T("shaded_list"), g_shadedList);
593
727
 
594
728
    m_history.Save(*cfg);
595
729
 
812
946
void PoeditFrame::OnQuit(wxCommandEvent&)
813
947
{
814
948
    Close(true);
 
949
#ifdef __WXMAC__
 
950
    // FIXME: do this always when we have both Quit and Exit items
 
951
    wxGetApp().ExitMainLoop();
 
952
#endif
815
953
}
816
954
 
817
955
 
818
956
 
819
957
void PoeditFrame::OnCloseWindow(wxCloseEvent&)
820
958
{
821
 
    UpdateFromTextCtrl();
822
959
    if (m_catalog && m_modified)
823
960
    {
824
961
        int r =
844
981
 
845
982
void PoeditFrame::OnOpen(wxCommandEvent&)
846
983
{
847
 
    UpdateFromTextCtrl();
848
984
    if (m_catalog && m_modified)
849
985
    {
850
986
        int r =
875
1011
        wxConfig::Get()->Write(_T("last_file_path"), wxPathOnly(name));
876
1012
        ReadCatalog(name);
877
1013
 
878
 
        if (gs_focusToText)
 
1014
        if (g_focusToText)
879
1015
            m_textTrans->SetFocus();
880
1016
        else
881
1017
            m_list->SetFocus();
886
1022
 
887
1023
void PoeditFrame::OnOpenHist(wxCommandEvent& event)
888
1024
{
889
 
    UpdateFromTextCtrl();
890
1025
    if (m_catalog && m_modified)
891
1026
    {
892
1027
        int r =
909
1044
    {
910
1045
        ReadCatalog(f);
911
1046
 
912
 
        if (gs_focusToText)
 
1047
        if (g_focusToText)
913
1048
            m_textTrans->SetFocus();
914
1049
        else
915
1050
            m_list->SetFocus();
939
1074
 
940
1075
    if (f.FileExists())
941
1076
    {
942
 
        UpdateFromTextCtrl();
943
1077
        if (m_catalog && m_modified)
944
1078
        {
945
1079
            int r =
967
1101
 
968
1102
void PoeditFrame::OnSave(wxCommandEvent& event)
969
1103
{
970
 
    UpdateFromTextCtrl();
971
1104
    if (m_fileName.empty())
972
1105
        OnSaveAs(event);
973
1106
    else
1014
1147
    if (filename.empty())
1015
1148
        return;
1016
1149
 
1017
 
    UpdateFromTextCtrl();
1018
 
 
1019
1150
    m_fileName = filename;
1020
1151
    WriteCatalog(filename);
1021
1152
}
1028
1159
 
1029
1160
void PoeditFrame::OnExport(wxCommandEvent&)
1030
1161
{
1031
 
    UpdateFromTextCtrl();
1032
 
 
1033
1162
    wxString name(wxFileNameFromPath(m_fileName));
1034
1163
 
1035
1164
    if (name.empty())
1063
1192
{
1064
1193
    bool isFromPOT = event.GetId() == XRCID("menu_new_from_pot");
1065
1194
 
1066
 
    UpdateFromTextCtrl();
1067
1195
    if (m_catalog && m_modified)
1068
1196
    {
1069
1197
        int r =
1162
1290
    {
1163
1291
        dlg.TransferFrom(m_catalog);
1164
1292
        m_modified = true;
1165
 
        UpdateFromTextCtrl();
1166
1293
        RecreatePluralTextCtrls();
1167
1294
        UpdateTitle();
1168
1295
        UpdateMenu();
1180
1307
    if (dlg.ShowModal() == wxID_OK)
1181
1308
    {
1182
1309
        dlg.TransferFrom(wxConfig::Get());
1183
 
        gs_focusToText = (bool)wxConfig::Get()->Read(_T("focus_to_text"),
 
1310
        g_focusToText = (bool)wxConfig::Get()->Read(_T("focus_to_text"),
1184
1311
                                                     (long)false);
 
1312
 
1185
1313
        SetCustomFonts();
 
1314
        m_list->Refresh(); // if font changed
 
1315
 
1186
1316
        UpdateCommentWindowEditable();
1187
1317
        InitSpellchecker();
1188
1318
    }
1196
1326
 
1197
1327
    CancelItemsValidation();
1198
1328
 
1199
 
    UpdateFromTextCtrl();
1200
 
 
1201
1329
    // This ensures that the list control won't be redrawn during Update()
1202
1330
    // call when a dialog box is hidden; another alternative would be to call
1203
1331
    // m_list->CatalogChanged(NULL) here
1223
1351
 
1224
1352
void PoeditFrame::OnUpdate(wxCommandEvent& event)
1225
1353
{
1226
 
    UpdateFromTextCtrl();
1227
 
 
1228
1354
    wxString pot_file;
1229
1355
 
1230
1356
    if (event.GetId() == XRCID("menu_update_from_pot"))
1259
1385
 
1260
1386
void PoeditFrame::OnListSel(wxListEvent& event)
1261
1387
{
1262
 
    if (m_sel != -1)
1263
 
        UpdateFromTextCtrl(m_sel);
1264
 
 
1265
1388
    wxWindow *focus = wxWindow::FindFocus();
1266
1389
    bool hasFocus = (focus == m_textTrans) ||
1267
1390
                    (focus && focus->GetParent() == m_pluralNotebook);
1268
1391
 
1269
1392
    event.Skip();
1270
1393
 
1271
 
    m_sel = event.GetIndex();
1272
 
    if ( !m_catalog || m_sel > (int)m_catalog->GetCount() )
1273
 
        m_sel = -1;
1274
 
 
1275
 
    UpdateToTextCtrl(m_sel);
 
1394
    UpdateToTextCtrl();
1276
1395
 
1277
1396
    if (hasFocus)
1278
1397
    {
1284
1403
}
1285
1404
 
1286
1405
 
1287
 
 
1288
 
void PoeditFrame::OnListDesel(wxListEvent& event)
1289
 
{
1290
 
    UpdateFromTextCtrl(event.GetIndex());
1291
 
    event.Skip();
1292
 
}
1293
 
 
1294
1406
void PoeditFrame::OnListActivated(wxListEvent& event)
1295
1407
{
1296
1408
    if (m_catalog)
1297
1409
    {
1298
1410
        int ind = m_list->GetIndexInCatalog(event.GetIndex());
1299
1411
        if (ind >= (int)m_catalog->GetCount()) return;
1300
 
        CatalogData& entry = (*m_catalog)[ind];
1301
 
        if (entry.GetValidity() == CatalogData::Val_Invalid)
 
1412
        CatalogItem& entry = (*m_catalog)[ind];
 
1413
        if (entry.GetValidity() == CatalogItem::Val_Invalid)
1302
1414
        {
1303
1415
            wxMessageBox(entry.GetErrorString(),
1304
1416
                         _("Gettext syntax error"),
1311
1423
 
1312
1424
void PoeditFrame::OnReferencesMenu(wxCommandEvent& event)
1313
1425
{
1314
 
    int selItem = m_list->GetIndexInCatalog(m_sel);
1315
 
    if (selItem < 0 || selItem >= (int)m_catalog->GetCount()) return;
 
1426
    CatalogItem *entry = GetCurrentItem();
 
1427
    if ( !entry )
 
1428
        return;
1316
1429
 
1317
 
    const wxArrayString& refs = (*m_catalog)[selItem].GetReferences();
 
1430
    const wxArrayString& refs = entry->GetReferences();
1318
1431
 
1319
1432
    if (refs.GetCount() == 0)
1320
1433
        wxMessageBox(_("No references to this string found."));
1331
1444
        if (result != -1)
1332
1445
            ShowReference(result);
1333
1446
    }
1334
 
 
1335
1447
}
1336
1448
 
1337
1449
 
1344
1456
 
1345
1457
void PoeditFrame::ShowReference(int num)
1346
1458
{
 
1459
    CatalogItem *entry = GetCurrentItem();
 
1460
    wxCHECK_RET( entry, _T("no entry selected") );
 
1461
 
1347
1462
    wxBusyCursor bcur;
1348
1463
 
1349
1464
    wxString basepath;
1369
1484
 
1370
1485
    if (wxConfig::Get()->Read(_T("open_editor_immediately"), (long)false))
1371
1486
    {
1372
 
        wxString ref =
1373
 
            (*m_catalog)[m_list->GetIndexInCatalog(m_sel)].GetReferences()[num];
 
1487
        wxString ref = entry->GetReferences()[num];
1374
1488
        // translate windows-style paths to Unix ones, which
1375
1489
        // are accepted on all platforms:
1376
1490
        ref.Replace(_T("\\"), _T("/"));
1379
1493
    else
1380
1494
    {
1381
1495
        FileViewer *w = new FileViewer(this, basepath,
1382
 
                                       (*m_catalog)[m_list->GetIndexInCatalog(m_sel)].GetReferences(),
 
1496
                                       entry->GetReferences(),
1383
1497
                                       num);
1384
1498
        if (w->FileOk())
1385
1499
            w->Show(true);
1402
1516
        GetToolBar()->ToggleTool(XRCID("menu_fuzzy"),
1403
1517
                                 GetMenuBar()->IsChecked(XRCID("menu_fuzzy")));
1404
1518
    }
1405
 
    m_edittedTextFuzzyChanged = true;
 
1519
 
 
1520
    // The user explicitly changed fuzzy status (e.g. to on). Normally, if the
 
1521
    // user edits an entry, it's fuzzy flag is cleared, but if the user sets
 
1522
    // fuzzy on to indicate the translation is problematic and then continues
 
1523
    // editing the entry, we do not want to annoy him by changing fuzzy back on
 
1524
    // every keystroke.
 
1525
    m_dontAutoclearFuzzyStatus = true;
 
1526
 
1406
1527
    UpdateFromTextCtrl();
1407
1528
}
1408
1529
 
1427
1548
 
1428
1549
void PoeditFrame::OnCommentWinFlag(wxCommandEvent& event)
1429
1550
{
1430
 
    UpdateFromTextCtrl();
1431
1551
    UpdateDisplayCommentWin();
1432
1552
}
1433
1553
 
1434
1554
void PoeditFrame::OnAutoCommentsWinFlag(wxCommandEvent& event)
1435
1555
{
1436
 
    UpdateFromTextCtrl();
1437
1556
    UpdateDisplayCommentWin();
1438
1557
}
1439
1558
 
1440
1559
 
1441
1560
void PoeditFrame::OnShadedListFlag(wxCommandEvent& event)
1442
1561
{
1443
 
    UpdateFromTextCtrl();
1444
 
    gs_shadedList = GetMenuBar()->IsChecked(XRCID("menu_shaded"));
 
1562
    g_shadedList = GetMenuBar()->IsChecked(XRCID("menu_shaded"));
1445
1563
    RefreshControls();
1446
1564
}
1447
1565
 
1504
1622
    f->Show(true);
1505
1623
}
1506
1624
 
 
1625
 
 
1626
CatalogItem *PoeditFrame::GetCurrentItem() const
 
1627
{
 
1628
    if ( !m_catalog || !m_list )
 
1629
        return NULL;
 
1630
 
 
1631
    int item = m_list->GetSelectedCatalogItem();
 
1632
    if ( item == -1 )
 
1633
        return NULL;
 
1634
 
 
1635
    wxASSERT( item >= 0 && item < m_catalog->GetCount() );
 
1636
 
 
1637
    return &(*m_catalog)[item];
 
1638
}
 
1639
 
 
1640
 
1507
1641
static wxString TransformNewval(const wxString& val, bool displayQuotes)
1508
1642
{
1509
1643
    wxString newval(val);
1536
1670
    return newval;
1537
1671
}
1538
1672
 
1539
 
void PoeditFrame::UpdateFromTextCtrl(int item)
 
1673
void PoeditFrame::UpdateFromTextCtrl()
1540
1674
{
1541
 
    if (m_catalog == NULL) return;
1542
 
    if (item == -1) item = m_sel;
1543
 
    if (m_sel == -1 || m_sel >= m_list->GetItemCount()) return;
1544
 
    int ind = m_list->GetIndexInCatalog(item);
1545
 
    if (ind >= (int)m_catalog->GetCount()) return;
1546
 
 
1547
 
    CatalogData& entry = (*m_catalog)[ind];
1548
 
 
1549
 
    wxString key = entry.GetString();
 
1675
    CatalogItem *entry = GetCurrentItem();
 
1676
    if ( !entry )
 
1677
        return;
 
1678
 
 
1679
    wxString key = entry->GetString();
1550
1680
    bool newfuzzy = GetToolBar()->GetToolState(XRCID("menu_fuzzy"));
1551
1681
 
 
1682
    const bool oldIsTranslated = entry->IsTranslated();
1552
1683
    bool allTranslated = true; // will be updated later
1553
1684
    bool anyTransChanged = false; // ditto
1554
1685
 
1555
 
    // check if anything changed:
1556
 
    if (entry.HasPlural())
1557
 
    {
1558
 
        wxASSERT( m_textTransPlural.size() == m_edittedTextOrig.size() );
1559
 
        size_t size = m_textTransPlural.size();
1560
 
 
1561
 
        for (size_t i = 0; i < size; i++)
1562
 
        {
1563
 
            wxString newval = m_textTransPlural[i]->GetValue();
1564
 
            if (m_edittedTextOrig.empty() ||
1565
 
                newval != m_edittedTextOrig[i])
1566
 
            {
1567
 
                anyTransChanged = true;
1568
 
            }
1569
 
            if ( newval.empty() )
1570
 
            {
1571
 
                allTranslated = false;
1572
 
            }
1573
 
        }
1574
 
    }
1575
 
    else
1576
 
    {
1577
 
        wxString newval = m_textTrans->GetValue();
1578
 
        anyTransChanged =
1579
 
            m_edittedTextOrig.empty() || newval != m_edittedTextOrig[0];
1580
 
        allTranslated = !newval.empty();
1581
 
    }
1582
 
 
1583
 
    if (entry.IsFuzzy() == newfuzzy && !anyTransChanged)
1584
 
        return; // not even fuzzy status changed, so return
1585
 
 
1586
 
    if (entry.HasPlural())
 
1686
    if (entry->HasPlural())
1587
1687
    {
1588
1688
        wxArrayString str;
1589
1689
        for (unsigned i = 0; i < m_textTransPlural.size(); i++)
1591
1691
            wxString val = TransformNewval(m_textTransPlural[i]->GetValue(),
1592
1692
                                           m_displayQuotes);
1593
1693
            str.Add(val);
1594
 
        }
1595
 
        entry.SetTranslations(str);
 
1694
            if ( val.empty() )
 
1695
                allTranslated = false;
 
1696
        }
 
1697
 
 
1698
        if ( str != entry->GetTranslations() )
 
1699
        {
 
1700
            anyTransChanged = true;
 
1701
            entry->SetTranslations(str);
 
1702
        }
1596
1703
    }
1597
1704
    else
1598
1705
    {
1599
1706
        wxString newval =
1600
1707
            TransformNewval(m_textTrans->GetValue(), m_displayQuotes);
1601
 
        entry.SetTranslation(newval);
1602
 
    }
1603
 
 
1604
 
    if (newfuzzy == entry.IsFuzzy() && !m_edittedTextFuzzyChanged)
 
1708
 
 
1709
        if ( newval.empty() )
 
1710
            allTranslated = false;
 
1711
 
 
1712
        if ( newval != entry->GetTranslation() )
 
1713
        {
 
1714
            anyTransChanged = true;
 
1715
            entry->SetTranslation(newval);
 
1716
        }
 
1717
    }
 
1718
 
 
1719
    if (entry->IsFuzzy() == newfuzzy && !anyTransChanged)
 
1720
    {
 
1721
        return; // not even fuzzy status changed, so return
 
1722
    }
 
1723
 
 
1724
    // did something affecting statistics change?
 
1725
    bool statisticsChanged = false;
 
1726
 
 
1727
    if (newfuzzy == entry->IsFuzzy() && !m_dontAutoclearFuzzyStatus)
1605
1728
        newfuzzy = false;
1606
 
    entry.SetFuzzy(newfuzzy);
 
1729
 
 
1730
 
1607
1731
    GetToolBar()->ToggleTool(XRCID("menu_fuzzy"), newfuzzy);
1608
1732
    GetMenuBar()->Check(XRCID("menu_fuzzy"), newfuzzy);
1609
1733
 
1610
 
 
1611
 
    entry.SetModified(true);
1612
 
    entry.SetAutomatic(false);
1613
 
    entry.SetTranslated(allTranslated);
1614
 
 
1615
 
    m_list->RefreshItem(item);
 
1734
    if ( entry->IsFuzzy() != newfuzzy )
 
1735
    {
 
1736
        entry->SetFuzzy(newfuzzy);
 
1737
        statisticsChanged = true;
 
1738
    }
 
1739
    if ( oldIsTranslated != allTranslated )
 
1740
    {
 
1741
        entry->SetTranslated(allTranslated);
 
1742
        statisticsChanged = true;
 
1743
    }
 
1744
    entry->SetModified(true);
 
1745
    entry->SetAutomatic(false);
 
1746
 
 
1747
    RefreshSelectedItem();
 
1748
 
 
1749
    if ( statisticsChanged )
 
1750
    {
 
1751
        UpdateStatusBar();
 
1752
    }
 
1753
    // else: no point in recomputing stats
1616
1754
 
1617
1755
    if (m_modified == false)
1618
1756
    {
1620
1758
        UpdateTitle();
1621
1759
    }
1622
1760
 
1623
 
    UpdateStatusBar();
1624
 
 
1625
1761
#if USE_GETTEXT_VALIDATION
1626
1762
    // check validity of this item:
1627
1763
    m_itemsToValidate.push_front(item);
1628
1764
#endif
1629
1765
}
1630
1766
 
1631
 
 
1632
 
void PoeditFrame::UpdateToTextCtrl(int item)
1633
 
{
1634
 
    if (m_catalog == NULL) return;
1635
 
    if (item == -1) item = m_sel;
1636
 
    if (item == -1 || item >= m_list->GetItemCount()) return;
1637
 
    int ind = m_list->GetIndexInCatalog(item);
1638
 
    if (ind >= (int)m_catalog->GetCount()) return;
1639
 
 
1640
 
    const CatalogData& entry = (*m_catalog)[ind];
 
1767
namespace
 
1768
{
 
1769
 
 
1770
struct EventHandlerDisabler
 
1771
{
 
1772
    EventHandlerDisabler(wxEvtHandler *h) : m_hnd(h)
 
1773
        { m_hnd->SetEvtHandlerEnabled(false); }
 
1774
    ~EventHandlerDisabler()
 
1775
        { m_hnd->SetEvtHandlerEnabled(true); }
 
1776
 
 
1777
    wxEvtHandler *m_hnd;
 
1778
};
 
1779
 
 
1780
void SetTranslationValue(wxTextCtrl *txt, const wxString& value)
 
1781
{
 
1782
    // disable EVT_TEXT forwarding -- the event is generated by
 
1783
    // programmatic changes to text controls' content and we *don't*
 
1784
    // want UpdateFromTextCtrl() to be called from here
 
1785
    EventHandlerDisabler disabler(txt->GetEventHandler());
 
1786
    txt->SetValue(value);
 
1787
}
 
1788
 
 
1789
} // anonymous namespace
 
1790
 
 
1791
void PoeditFrame::UpdateToTextCtrl()
 
1792
{
 
1793
    CatalogItem *entry = GetCurrentItem();
 
1794
    if ( !entry )
 
1795
        return;
1641
1796
 
1642
1797
    wxString quote;
1643
1798
    wxString t_o, t_t, t_c, t_ac;
1644
 
    if (m_displayQuotes) quote = _T("\""); else quote = wxEmptyString;
1645
 
    t_o = quote + entry.GetString() + quote;
 
1799
    if (m_displayQuotes)
 
1800
        quote = _T("\"");
 
1801
    t_o = quote + entry->GetString() + quote;
1646
1802
    t_o.Replace(_T("\\n"), _T("\\n\n"));
1647
 
    t_c = entry.GetComment();
 
1803
    t_c = entry->GetComment();
1648
1804
    t_c.Replace(_T("\\n"), _T("\\n\n"));
1649
1805
 
1650
 
    for (unsigned i=0; i < entry.GetAutoComments().GetCount(); i++)
1651
 
      t_ac += entry.GetAutoComments()[i] + _T("\n");
 
1806
    for (unsigned i=0; i < entry->GetAutoComments().GetCount(); i++)
 
1807
      t_ac += entry->GetAutoComments()[i] + _T("\n");
1652
1808
    t_ac.Replace(_T("\\n"), _T("\\n\n"));
1653
1809
 
1654
1810
    // remove "# " in front of every comment line
1656
1812
 
1657
1813
    m_textOrig->SetValue(t_o);
1658
1814
 
1659
 
    m_edittedTextOrig.clear();
1660
 
 
1661
 
    if (entry.HasPlural())
 
1815
    if (entry->HasPlural())
1662
1816
    {
1663
 
        wxString t_op = quote + entry.GetPluralString() + quote;
 
1817
        wxString t_op = quote + entry->GetPluralString() + quote;
1664
1818
        t_op.Replace(_T("\\n"), _T("\\n\n"));
1665
1819
        m_textOrigPlural->SetValue(t_op);
1666
1820
 
1667
1821
        size_t formsCnt = m_textTransPlural.size();
1668
1822
        for (size_t j = 0; j < formsCnt; j++)
1669
 
            m_textTransPlural[j]->SetValue(wxEmptyString);
 
1823
            SetTranslationValue(m_textTransPlural[j], wxEmptyString);
1670
1824
 
1671
1825
        size_t i = 0;
1672
 
        for (i = 0; i < std::min(formsCnt, entry.GetNumberOfTranslations()); i++)
 
1826
        for (i = 0; i < std::min(formsCnt, entry->GetNumberOfTranslations()); i++)
1673
1827
        {
1674
 
            t_t = quote + entry.GetTranslation(i) + quote;
 
1828
            t_t = quote + entry->GetTranslation(i) + quote;
1675
1829
            t_t.Replace(_T("\\n"), _T("\\n\n"));
1676
 
            m_textTransPlural[i]->SetValue(t_t);
 
1830
            SetTranslationValue(m_textTransPlural[i], t_t);
1677
1831
            if (m_displayQuotes)
1678
1832
                m_textTransPlural[i]->SetInsertionPoint(1);
1679
 
            m_edittedTextOrig.push_back(t_t);
1680
1833
        }
1681
 
        // fill in remaining unset values:
1682
 
        for (; i < formsCnt; i++)
1683
 
            m_edittedTextOrig.push_back(_T(""));
1684
1834
    }
1685
1835
    else
1686
1836
    {
1687
 
        t_t = quote + entry.GetTranslation() + quote;
 
1837
        t_t = quote + entry->GetTranslation() + quote;
1688
1838
        t_t.Replace(_T("\\n"), _T("\\n\n"));
1689
 
        m_textTrans->SetValue(t_t);
 
1839
        SetTranslationValue(m_textTrans, t_t);
1690
1840
        if (m_displayQuotes)
1691
1841
            m_textTrans->SetInsertionPoint(1);
1692
 
        m_edittedTextOrig.push_back(t_t);
1693
1842
    }
1694
1843
 
1695
1844
    if (m_displayCommentWin)
1698
1847
    if (m_displayAutoCommentsWin)
1699
1848
        m_textAutoComments->SetValue(t_ac);
1700
1849
 
1701
 
    m_edittedTextFuzzyChanged = false;
1702
 
    GetToolBar()->ToggleTool(XRCID("menu_fuzzy"), entry.IsFuzzy());
1703
 
    GetMenuBar()->Check(XRCID("menu_fuzzy"), entry.IsFuzzy());
1704
 
 
1705
 
    ShowPluralFormUI(entry.HasPlural());
 
1850
    // by default, editing fuzzy item unfuzzies it
 
1851
    m_dontAutoclearFuzzyStatus = false;
 
1852
 
 
1853
    GetToolBar()->ToggleTool(XRCID("menu_fuzzy"), entry->IsFuzzy());
 
1854
    GetMenuBar()->Check(XRCID("menu_fuzzy"), entry->IsFuzzy());
 
1855
 
 
1856
    ShowPluralFormUI(entry->HasPlural());
1706
1857
}
1707
1858
 
1708
1859
 
1723
1874
    // don't call this, it's called from RefreshControls below:
1724
1875
    //m_list->CatalogChanged(m_catalog);
1725
1876
 
1726
 
    dynamic_cast<TextctrlHandler*>(m_textTrans->GetEventHandler())->SetCatalog(m_catalog);
1727
 
 
1728
1877
#ifdef USE_TRANSMEM
1729
1878
    if (m_transMem)
1730
1879
    {
1753
1902
 
1754
1903
void PoeditFrame::RefreshControls()
1755
1904
{
1756
 
    if (!m_catalog) return;
 
1905
    m_itemsRefreshQueue.clear();
 
1906
 
 
1907
    if (!m_catalog)
 
1908
        return;
1757
1909
 
1758
1910
    m_hasObsoleteItems = false;
1759
1911
    if (!m_catalog->IsOk())
1760
1912
    {
1761
 
        wxLogError(_("Error loading message catalog file '") + m_fileName + _("'."));
 
1913
        wxLogError(_("Error loading message catalog file '%s'."), m_fileName.c_str());
1762
1914
        m_fileName = wxEmptyString;
1763
1915
        UpdateMenu();
1764
1916
        UpdateTitle();
1773
1925
 
1774
1926
    // remember currently selected item:
1775
1927
    int selectedItem = m_list->GetSelectedCatalogItem();
1776
 
    // NB: This will force Poedit to not update to/from text controls when
1777
 
    //     selected item in list control changes in the code bellow, but the
1778
 
    //     _catalog item_ selected is still the same:
1779
 
    m_sel = -1;
1780
1928
 
1781
1929
    // update catalog view, this may involve reordering the items...
1782
1930
    m_list->CatalogChanged(m_catalog);
1783
1931
 
1784
1932
    // ...and so we need to restore selection now:
1785
1933
    if ( selectedItem != -1 )
1786
 
    {
1787
1934
        m_list->SelectCatalogItem(selectedItem);
1788
 
        m_sel = m_list->GetSelection();
1789
 
    }
1790
1935
 
1791
1936
    FindFrame *f = (FindFrame*)FindWindow(_T("find_frame"));
1792
1937
    if (f)
1852
1997
    wxMenuBar *menubar = GetMenuBar();
1853
1998
    wxToolBar *toolbar = GetToolBar();
1854
1999
 
1855
 
    if (m_catalog == NULL)
1856
 
    {
1857
 
        menubar->Enable(wxID_SAVE, false);
1858
 
        menubar->Enable(wxID_SAVEAS, false);
1859
 
        menubar->Enable(XRCID("menu_export"), false);
1860
 
        toolbar->EnableTool(wxID_SAVE, false);
1861
 
        toolbar->EnableTool(XRCID("menu_update"), false);
1862
 
        toolbar->EnableTool(XRCID("menu_fuzzy"), false);
1863
 
        toolbar->EnableTool(XRCID("menu_comment"), false);
1864
 
        menubar->EnableTop(1, false);
1865
 
        menubar->EnableTop(2, false);
1866
 
        m_textTrans->Enable(false);
1867
 
        m_textOrig->Enable(false);
1868
 
        m_textOrigPlural->Enable(false);
1869
 
        m_textComment->Enable(false);
1870
 
        m_textAutoComments->Enable(false);
1871
 
        m_list->Enable(false);
1872
 
    }
1873
 
    else
1874
 
    {
1875
 
        menubar->Enable(wxID_SAVE, true);
1876
 
        menubar->Enable(wxID_SAVEAS, true);
1877
 
        menubar->Enable(XRCID("menu_export"), true);
1878
 
        toolbar->EnableTool(wxID_SAVE, true);
1879
 
        toolbar->EnableTool(XRCID("menu_fuzzy"), true);
1880
 
        toolbar->EnableTool(XRCID("menu_comment"), true);
1881
 
        menubar->EnableTop(1, true);
1882
 
        menubar->EnableTop(2, true);
1883
 
        m_textTrans->Enable(true);
1884
 
        m_textOrig->Enable(true);
1885
 
        m_textOrigPlural->Enable(true);
1886
 
        m_textComment->Enable(true);
1887
 
        m_textAutoComments->Enable(true);
1888
 
        m_list->Enable(true);
1889
 
        bool doupdate = m_catalog->Header().SearchPaths.GetCount() > 0;
1890
 
        toolbar->EnableTool(XRCID("menu_update"), doupdate);
1891
 
        menubar->Enable(XRCID("menu_update"), doupdate);
1892
 
        menubar->Enable(XRCID("menu_purge_deleted"),
1893
 
                             m_catalog->HasDeletedItems());
 
2000
    const bool editable = (m_catalog != NULL);
 
2001
 
 
2002
    menubar->Enable(wxID_SAVE, editable);
 
2003
    menubar->Enable(wxID_SAVEAS, editable);
 
2004
    menubar->Enable(XRCID("menu_export"), editable);
 
2005
    toolbar->EnableTool(wxID_SAVE, editable);
 
2006
    toolbar->EnableTool(XRCID("menu_update"), editable);
 
2007
    toolbar->EnableTool(XRCID("menu_fuzzy"), editable);
 
2008
    toolbar->EnableTool(XRCID("menu_comment"), editable);
 
2009
 
 
2010
    menubar->Enable(XRCID("menu_update"), editable);
 
2011
    menubar->Enable(XRCID("menu_fuzzy"), editable);
 
2012
    menubar->Enable(XRCID("menu_comment"), editable);
 
2013
    menubar->Enable(XRCID("menu_insert_orig"), editable);
 
2014
    menubar->Enable(XRCID("menu_references"), editable);
 
2015
    menubar->Enable(XRCID("menu_find"), editable);
 
2016
 
 
2017
    menubar->EnableTop(2, editable);
 
2018
 
 
2019
    m_textTrans->Enable(editable);
 
2020
    m_textOrig->Enable(editable);
 
2021
    m_textOrigPlural->Enable(editable);
 
2022
    m_textComment->Enable(editable);
 
2023
    m_textAutoComments->Enable(editable);
 
2024
    m_list->Enable(editable);
 
2025
 
 
2026
    menubar->Enable(XRCID("menu_purge_deleted"),
 
2027
                    editable && m_catalog->HasDeletedItems());
 
2028
 
 
2029
    const bool doupdate = editable &&
 
2030
                          m_catalog->Header().SearchPaths.GetCount() > 0;
 
2031
    toolbar->EnableTool(XRCID("menu_update"), doupdate);
 
2032
    menubar->Enable(XRCID("menu_update"), doupdate);
1894
2033
 
1895
2034
#ifdef __WXGTK__
 
2035
    if (!editable)
 
2036
    {
1896
2037
        // work around a wxGTK bug: enabling wxTextCtrl makes it editable too
1897
2038
        // in wxGTK <= 2.8:
1898
2039
        m_textOrig->SetEditable(false);
1899
2040
        m_textOrigPlural->SetEditable(false);
 
2041
    }
1900
2042
#endif
1901
 
    }
1902
2043
 
1903
 
    menubar->EnableTop(4, m_catalog != NULL);
 
2044
    menubar->EnableTop(4, editable);
1904
2045
    for (int i = 0; i < 10; i++)
1905
2046
    {
1906
 
        menubar->Enable(ID_BOOKMARK_SET + i, m_catalog != NULL);
 
2047
        menubar->Enable(ID_BOOKMARK_SET + i, editable);
1907
2048
        menubar->Enable(ID_BOOKMARK_GO + i,
1908
 
                        m_catalog != NULL &&
 
2049
                        editable &&
1909
2050
                        m_catalog->GetBookmarkIndex(Bookmark(i)) != -1);
1910
2051
    }
1911
2052
}
1933
2074
        size_t cnt = m_catalog->GetCount();
1934
2075
        for (size_t i = 0; i < cnt; i++)
1935
2076
        {
1936
 
            CatalogData& dt = (*m_catalog)[i];
 
2077
            CatalogItem& dt = (*m_catalog)[i];
1937
2078
            if (dt.IsModified() && !dt.IsFuzzy() &&
1938
 
                dt.GetValidity() == CatalogData::Val_Valid &&
 
2079
                dt.GetValidity() == CatalogItem::Val_Valid &&
1939
2080
                !dt.GetTranslation().empty())
1940
2081
            {
1941
2082
                tm->Store(dt.GetString(), dt.GetTranslation());
1958
2099
 
1959
2100
void PoeditFrame::OnEditComment(wxCommandEvent& event)
1960
2101
{
1961
 
    int selItem = m_list->GetIndexInCatalog(m_sel);
1962
 
    if (selItem < 0 || selItem >= (int)m_catalog->GetCount()) return;
 
2102
    CatalogItem *entry = GetCurrentItem();
 
2103
    wxCHECK_RET( entry, _T("no entry selected") );
1963
2104
 
1964
 
    wxString comment = (*m_catalog)[selItem].GetComment();
 
2105
    wxString comment = entry->GetComment();
1965
2106
    CommentDialog dlg(this, comment);
1966
2107
    if (dlg.ShowModal() == wxID_OK)
1967
2108
    {
1968
2109
        m_modified = true;
1969
2110
        UpdateTitle();
1970
2111
        comment = dlg.GetComment();
1971
 
        (*m_catalog)[selItem].SetComment(comment);
 
2112
        entry->SetComment(comment);
1972
2113
 
1973
 
        m_list->RefreshItem(m_sel);
 
2114
        RefreshSelectedItem();
1974
2115
 
1975
2116
        // update comment window
1976
2117
        m_textComment->SetValue(CommentDialog::RemoveStartHash(comment));
1995
2136
#ifdef USE_TRANSMEM
1996
2137
void PoeditFrame::OnAutoTranslate(wxCommandEvent& event)
1997
2138
{
 
2139
    CatalogItem *entry = GetCurrentItem();
 
2140
    wxCHECK_RET( entry, _T("no entry selected") );
 
2141
 
1998
2142
    int ind = event.GetId() - ID_POPUP_TRANS;
1999
 
    (*m_catalog)[m_list->GetIndexInCatalog(m_sel)].SetTranslation(m_autoTranslations[ind]);
 
2143
    entry->SetTranslation(m_autoTranslations[ind]);
2000
2144
    UpdateToTextCtrl();
2001
 
    // VS: This dirty trick ensures proper refresh of everything:
2002
 
    m_edittedTextOrig.clear();
2003
 
    m_edittedTextFuzzyChanged = false;
2004
 
    UpdateFromTextCtrl();
 
2145
    RefreshSelectedItem();
2005
2146
}
2006
2147
 
2007
2148
void PoeditFrame::OnAutoTranslateAll(wxCommandEvent& event)
2027
2168
    pi.SetGaugeMax(cnt);
2028
2169
    for (size_t i = 0; i < cnt; i++)
2029
2170
    {
2030
 
        CatalogData& dt = (*m_catalog)[i];
 
2171
        CatalogItem& dt = (*m_catalog)[i];
2031
2172
        if (dt.IsFuzzy() || !dt.IsTranslated())
2032
2173
        {
2033
2174
            wxArrayString results;
2094
2235
#endif
2095
2236
 
2096
2237
        wxBusyCursor bcur;
2097
 
        CatalogData& dt = (*m_catalog)[item];
 
2238
        CatalogItem& dt = (*m_catalog)[item];
2098
2239
        m_autoTranslations.Clear();
2099
2240
        if (GetTransMem()->Lookup(dt.GetString(), m_autoTranslations) > 0)
2100
2241
        {
2121
2262
 
2122
2263
void PoeditFrame::OnAbout(wxCommandEvent&)
2123
2264
{
2124
 
    wxBusyCursor busy;
2125
 
    wxDialog dlg;
2126
 
    wxXmlResource::Get()->LoadDialog(&dlg, this, _T("about_box"));
2127
 
    wxString version = wxString(_("version")) + _T(" ") + wxGetApp().GetAppVersion();
2128
 
    XRCCTRL(dlg, "version", wxStaticText)->SetLabel(version);
2129
 
 
2130
 
    dlg.GetSizer()->RecalcSizes();
2131
 
    dlg.Layout();
2132
 
    dlg.Centre();
2133
 
    dlg.ShowModal();
 
2265
    wxAboutDialogInfo about;
 
2266
 
 
2267
    about.SetName(_T("Poedit"));
 
2268
    about.SetVersion(wxGetApp().GetAppVersion());
 
2269
    about.SetDescription(_("Poedit is an easy to use translations editor."));
 
2270
    about.SetCopyright(_T("Copyright \u00a9 1999-2008 Vaclav Slavik"));
 
2271
#ifdef __WXGTK__ // other ports would show non-native about dlg
 
2272
    about.SetWebSite(_T("http://www.poedit.net"));
 
2273
#endif
 
2274
 
 
2275
    wxAboutBox(about);
2134
2276
}
2135
2277
 
2136
2278
 
2163
2305
{
2164
2306
    wxConfigBase *cfg = wxConfig::Get();
2165
2307
 
2166
 
    static bool prevUseFontList = false;
2167
2308
    static bool prevUseFontText = false;
2168
2309
 
2169
2310
    bool useFontList = (bool)cfg->Read(_T("custom_font_list_use"), (long)false);
2178
2319
            fi.FromString(name);
2179
2320
            wxFont font;
2180
2321
            font.SetNativeFontInfo(fi);
2181
 
            m_list->SetFont(font);
2182
 
            prevUseFontList = true;
 
2322
            m_list->SetCustomFont(font);
2183
2323
        }
2184
2324
    }
2185
 
    else if (prevUseFontList)
 
2325
    else
2186
2326
    {
2187
 
        m_list->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2188
 
        prevUseFontList = false;
 
2327
        m_list->SetCustomFont(wxNullFont);
2189
2328
    }
2190
2329
 
2191
2330
    if (useFontText)
2237
2376
            m_textComment = new wxTextCtrl(m_bottomRightPanel,
2238
2377
                                        ID_TEXTCOMMENT, wxEmptyString,
2239
2378
                                        wxDefaultPosition, wxDefaultSize,
2240
 
                                        wxTE_MULTILINE);
 
2379
                                        wxTE_MULTILINE | wxTE_RICH2);
2241
2380
        }
2242
2381
        else
2243
2382
        {
2244
2383
            m_textComment = new UnfocusableTextCtrl(m_bottomRightPanel,
2245
2384
                                        ID_TEXTCOMMENT, wxEmptyString,
2246
2385
                                        wxDefaultPosition, wxDefaultSize,
2247
 
                                        wxTE_MULTILINE | wxTE_READONLY);
 
2386
                                        wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY);
2248
2387
        }
2249
2388
        UpdateDisplayCommentWin();
2250
2389
    }
2302
2441
    if (!m_commentWindowEditable)
2303
2442
        return;
2304
2443
 
 
2444
    CatalogItem *entry = GetCurrentItem();
 
2445
    wxCHECK_RET( entry, _T("no entry selected") );
 
2446
 
2305
2447
    wxString comment;
2306
2448
    comment = CommentDialog::AddStartHash(m_textComment->GetValue());
2307
 
    CatalogData& data((*m_catalog)[m_list->GetIndexInCatalog(m_sel)]);
2308
2449
 
2309
 
    if (comment == data.GetComment())
 
2450
    if (comment == entry->GetComment())
2310
2451
        return;
2311
2452
 
2312
 
    data.SetComment(comment);
2313
 
 
2314
 
    m_list->RefreshItem(m_sel);
 
2453
    entry->SetComment(comment);
 
2454
    RefreshSelectedItem();
2315
2455
 
2316
2456
    if (m_modified == false)
2317
2457
    {
2321
2461
}
2322
2462
 
2323
2463
 
 
2464
void PoeditFrame::RefreshSelectedItem()
 
2465
{
 
2466
    m_itemsRefreshQueue.insert(m_list->GetSelection());
 
2467
}
 
2468
 
2324
2469
void PoeditFrame::OnIdle(wxIdleEvent& event)
2325
2470
{
 
2471
    event.Skip();
 
2472
 
2326
2473
#if USE_GETTEXT_VALIDATION
2327
2474
    if (!m_itemsToValidate.empty() && m_itemBeingValidated == -1)
2328
2475
        BeginItemValidation();
2329
2476
#endif
2330
 
    event.Skip();
 
2477
 
 
2478
    for ( std::set<int>::const_iterator i = m_itemsRefreshQueue.begin();
 
2479
          i != m_itemsRefreshQueue.end(); ++i )
 
2480
    {
 
2481
        m_list->RefreshItem(*i);
 
2482
    }
 
2483
    m_itemsRefreshQueue.clear();
2331
2484
}
2332
2485
 
2333
2486
void PoeditFrame::OnEndProcess(wxProcessEvent& event)
2364
2517
#if USE_GETTEXT_VALIDATION
2365
2518
    int item = m_itemsToValidate.front();
2366
2519
    int index = m_list->GetIndexInCatalog(item);
2367
 
    CatalogData& dt = (*m_catalog)[index];
 
2520
    CatalogItem& dt = (*m_catalog)[index];
2368
2521
 
2369
2522
    if (!dt.IsTranslated())
2370
2523
        return;
2371
2524
 
2372
 
    if (dt.GetValidity() != CatalogData::Val_Unknown)
 
2525
    if (dt.GetValidity() != CatalogItem::Val_Unknown)
2373
2526
        return;
2374
2527
 
2375
2528
    // run this entry through msgfmt (in a single-entry catalog) to check if
2376
2529
    // it is correct:
2377
2530
    Catalog cat;
2378
 
    cat.AddItem(new CatalogData(dt));
 
2531
    cat.AddItem(new CatalogItem(dt));
2379
2532
 
2380
2533
    if (m_catalog->Header().HasHeader(_T("Plural-Forms")))
2381
2534
    {
2420
2573
    {
2421
2574
        int item = m_itemBeingValidated;
2422
2575
        int index = m_list->GetIndexInCatalog(item);
2423
 
        CatalogData& dt = (*m_catalog)[index];
 
2576
        CatalogItem& dt = (*m_catalog)[index];
2424
2577
 
2425
2578
        bool ok = (m_validationProcess.ExitCode == 0);
2426
2579
        dt.SetValidity(ok);
2485
2638
void PoeditFrame::RecreatePluralTextCtrls()
2486
2639
{
2487
2640
    for (size_t i = 0; i < m_textTransPlural.size(); i++)
2488
 
        m_textTransPlural[i]->PopEventHandler(true/*delete*/);
 
2641
       m_textTransPlural[i]->PopEventHandler(true/*delete*/);
2489
2642
    m_textTransPlural.clear();
2490
2643
    m_pluralNotebook->DeleteAllPages();
2491
2644
    m_textTransSingularForm = NULL;
2526
2679
        wxTextCtrl *txt = new wxTextCtrl(m_pluralNotebook, -1,
2527
2680
                                         wxEmptyString,
2528
2681
                                         wxDefaultPosition, wxDefaultSize,
2529
 
                                         wxTE_MULTILINE);
2530
 
        txt->PushEventHandler(new TextctrlHandler(this));
 
2682
                                         wxTE_MULTILINE | wxTE_RICH2);
 
2683
        txt->PushEventHandler(new TransTextctrlHandler(this));
2531
2684
        m_textTransPlural.push_back(txt);
2532
2685
        m_pluralNotebook->AddPage(txt, desc);
2533
2686
 
2553
2706
        list->SetItemState(item, wxLIST_STATE_SELECTED,
2554
2707
                                 wxLIST_STATE_SELECTED);
2555
2708
 
2556
 
    wxMenu *menu = GetPopupMenu(m_list->GetIndexInCatalog(m_sel));
 
2709
    wxMenu *menu = GetPopupMenu(m_list->GetSelectedCatalogItem());
2557
2710
    if (menu)
2558
2711
    {
2559
2712
        list->PopupMenu(menu, event.GetPosition());
2564
2717
 
2565
2718
void PoeditFrame::OnListFocus(wxFocusEvent& event)
2566
2719
{
2567
 
    if (gs_focusToText)
 
2720
    if (g_focusToText)
2568
2721
    {
2569
2722
        if (m_textTrans->IsShown())
2570
2723
            m_textTrans->SetFocus();
2627
2780
    // Set bookmark if different from the current value for the item,
2628
2781
    // else unset it
2629
2782
    int bkIndex = -1;
2630
 
    int selItemIndex = m_list->GetIndexInCatalog(m_sel);
 
2783
    int selItemIndex = m_list->GetSelectedCatalogItem();
2631
2784
 
2632
2785
    Bookmark bk = static_cast<Bookmark>(event.GetId() - ID_BOOKMARK_SET);
2633
2786
    if (m_catalog->GetBookmarkIndex(bk) == selItemIndex)
2640
2793
    }
2641
2794
 
2642
2795
    // Refresh items
2643
 
    m_list->RefreshItem(m_sel);
 
2796
    RefreshSelectedItem();
2644
2797
    if (bkIndex != -1)
2645
2798
        m_list->RefreshItem(m_list->GetItemIndex(bkIndex));
2646
2799