160
156
class TextctrlHandler : public wxEvtHandler
163
TextctrlHandler(PoeditFrame* frame) :
164
wxEvtHandler(), m_frame(frame), m_list(frame->m_list), m_sel(&(frame->m_sel)) {}
166
void SetCatalog(Catalog* catalog) {m_catalog = catalog;}
159
TextctrlHandler(PoeditFrame* frame) : m_list(frame->m_list) {}
169
162
void OnKeyDown(wxKeyEvent& event)
171
164
int keyCode = event.GetKeyCode();
173
if (!event.ControlDown())
165
int modifiers = event.GetModifiers();
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;
173
if ( modifiers != wxMOD_CMD ) // Cmd-* or Ctrl-*
179
int sel = m_list->GetSelection();
185
m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
187
m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
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);
194
if ((*m_sel < m_list->GetItemCount() - 1))
196
if ((sel < m_list->GetItemCount() - 1))
197
m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
199
m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
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);
216
218
case WXK_PAGEDOWN:
219
m_list->SetItemState(*m_sel, 0, wxLIST_STATE_SELECTED);
221
m_list->SetItemState(sel, 0, wxLIST_STATE_SELECTED);
221
int newy = *m_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);
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:
238
wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
247
wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
256
wxTextCtrl *txt = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
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
280
bool DoCopy(wxTextCtrl *textctrl)
283
textctrl->GetSelection(&from, &to);
287
const wxString sel = textctrl->GetRange(from, to);
289
wxClipboardLocker lock;
290
wxCHECK_MSG( !!lock, false, _T("failed to lock clipboard") );
292
wxClipboard::Get()->SetData(new wxTextDataObject(sel));
296
void OnCopy(wxClipboardTextEvent& event)
298
wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
299
wxCHECK_RET( textctrl, _T("wrong use of event handler") );
304
void OnCut(wxClipboardTextEvent& event)
306
wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
307
wxCHECK_RET( textctrl, _T("wrong use of event handler") );
309
if ( !DoCopy(textctrl) )
313
textctrl->GetSelection(&from, &to);
314
textctrl->Remove(from, to);
317
void OnPaste(wxClipboardTextEvent& event)
319
wxTextCtrl *textctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
320
wxCHECK_RET( textctrl, _T("wrong use of event handler") );
322
wxClipboardLocker lock;
323
wxCHECK_RET( !!lock, _T("failed to lock clipboard") );
326
wxClipboard::Get()->GetData(d);
329
textctrl->GetSelection(&from, &to);
330
textctrl->Replace(from, to, d.GetText());
233
334
DECLARE_EVENT_TABLE()
235
PoeditFrame *m_frame;
236
336
PoeditListCtrl *m_list;
240
338
friend class ListHandler;
243
341
BEGIN_EVENT_TABLE(TextctrlHandler, wxEvtHandler)
244
EVT_KEY_DOWN(TextctrlHandler::OnKeyDown)
342
EVT_KEY_DOWN(TextctrlHandler::OnKeyDown)
344
EVT_TEXT_COPY(-1, TextctrlHandler::OnCopy)
345
EVT_TEXT_CUT(-1, TextctrlHandler::OnCut)
346
EVT_TEXT_PASTE(-1, TextctrlHandler::OnPaste)
351
class TransTextctrlHandler : public TextctrlHandler
354
TransTextctrlHandler(PoeditFrame* frame)
355
: TextctrlHandler(frame), m_frame(frame) {}
358
void OnText(wxCommandEvent& event)
360
m_frame->UpdateFromTextCtrl();
364
PoeditFrame *m_frame;
366
DECLARE_EVENT_TABLE()
369
BEGIN_EVENT_TABLE(TransTextctrlHandler, TextctrlHandler)
370
EVT_TEXT(-1, TransTextctrlHandler::OnText)
247
374
// special handling of events in listctrl
248
375
class ListHandler : public wxEvtHandler
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);
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)));
396
524
SetIcon(wxICON(appicon));
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);
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
445
573
if (ms_instances.GetCount() == 0)
446
SetSize(posx, posy, width, height);
448
SetSize(-1, -1, width, height);
575
SetClientSize(width, height);
449
576
if (cfg->Read(_T("frame_maximized"), long(0)))
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);
489
621
m_textTrans = new wxTextCtrl(m_bottomLeftPanel,
490
622
ID_TEXTTRANS, wxEmptyString,
491
623
wxDefaultPosition, wxDefaultSize,
624
wxTE_MULTILINE | wxTE_RICH2);
494
626
// in case of plurals form, this is the control for n=1:
495
627
m_textTransSingularForm = NULL;
1539
void PoeditFrame::UpdateFromTextCtrl(int item)
1673
void PoeditFrame::UpdateFromTextCtrl()
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;
1547
CatalogData& entry = (*m_catalog)[ind];
1549
wxString key = entry.GetString();
1675
CatalogItem *entry = GetCurrentItem();
1679
wxString key = entry->GetString();
1550
1680
bool newfuzzy = GetToolBar()->GetToolState(XRCID("menu_fuzzy"));
1682
const bool oldIsTranslated = entry->IsTranslated();
1552
1683
bool allTranslated = true; // will be updated later
1553
1684
bool anyTransChanged = false; // ditto
1555
// check if anything changed:
1556
if (entry.HasPlural())
1558
wxASSERT( m_textTransPlural.size() == m_edittedTextOrig.size() );
1559
size_t size = m_textTransPlural.size();
1561
for (size_t i = 0; i < size; i++)
1563
wxString newval = m_textTransPlural[i]->GetValue();
1564
if (m_edittedTextOrig.empty() ||
1565
newval != m_edittedTextOrig[i])
1567
anyTransChanged = true;
1569
if ( newval.empty() )
1571
allTranslated = false;
1577
wxString newval = m_textTrans->GetValue();
1579
m_edittedTextOrig.empty() || newval != m_edittedTextOrig[0];
1580
allTranslated = !newval.empty();
1583
if (entry.IsFuzzy() == newfuzzy && !anyTransChanged)
1584
return; // not even fuzzy status changed, so return
1586
if (entry.HasPlural())
1686
if (entry->HasPlural())
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);
1595
entry.SetTranslations(str);
1695
allTranslated = false;
1698
if ( str != entry->GetTranslations() )
1700
anyTransChanged = true;
1701
entry->SetTranslations(str);
1599
1706
wxString newval =
1600
1707
TransformNewval(m_textTrans->GetValue(), m_displayQuotes);
1601
entry.SetTranslation(newval);
1604
if (newfuzzy == entry.IsFuzzy() && !m_edittedTextFuzzyChanged)
1709
if ( newval.empty() )
1710
allTranslated = false;
1712
if ( newval != entry->GetTranslation() )
1714
anyTransChanged = true;
1715
entry->SetTranslation(newval);
1719
if (entry->IsFuzzy() == newfuzzy && !anyTransChanged)
1721
return; // not even fuzzy status changed, so return
1724
// did something affecting statistics change?
1725
bool statisticsChanged = false;
1727
if (newfuzzy == entry->IsFuzzy() && !m_dontAutoclearFuzzyStatus)
1605
1728
newfuzzy = false;
1606
entry.SetFuzzy(newfuzzy);
1607
1731
GetToolBar()->ToggleTool(XRCID("menu_fuzzy"), newfuzzy);
1608
1732
GetMenuBar()->Check(XRCID("menu_fuzzy"), newfuzzy);
1611
entry.SetModified(true);
1612
entry.SetAutomatic(false);
1613
entry.SetTranslated(allTranslated);
1615
m_list->RefreshItem(item);
1734
if ( entry->IsFuzzy() != newfuzzy )
1736
entry->SetFuzzy(newfuzzy);
1737
statisticsChanged = true;
1739
if ( oldIsTranslated != allTranslated )
1741
entry->SetTranslated(allTranslated);
1742
statisticsChanged = true;
1744
entry->SetModified(true);
1745
entry->SetAutomatic(false);
1747
RefreshSelectedItem();
1749
if ( statisticsChanged )
1753
// else: no point in recomputing stats
1617
1755
if (m_modified == false)
1625
1761
#if USE_GETTEXT_VALIDATION
1626
1762
// check validity of this item:
1627
1763
m_itemsToValidate.push_front(item);
1632
void PoeditFrame::UpdateToTextCtrl(int item)
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;
1640
const CatalogData& entry = (*m_catalog)[ind];
1770
struct EventHandlerDisabler
1772
EventHandlerDisabler(wxEvtHandler *h) : m_hnd(h)
1773
{ m_hnd->SetEvtHandlerEnabled(false); }
1774
~EventHandlerDisabler()
1775
{ m_hnd->SetEvtHandlerEnabled(true); }
1777
wxEvtHandler *m_hnd;
1780
void SetTranslationValue(wxTextCtrl *txt, const wxString& value)
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);
1789
} // anonymous namespace
1791
void PoeditFrame::UpdateToTextCtrl()
1793
CatalogItem *entry = GetCurrentItem();
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)
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"));
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"));
1654
1810
// remove "# " in front of every comment line
1657
1813
m_textOrig->SetValue(t_o);
1659
m_edittedTextOrig.clear();
1661
if (entry.HasPlural())
1815
if (entry->HasPlural())
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);
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);
1672
for (i = 0; i < std::min(formsCnt, entry.GetNumberOfTranslations()); i++)
1826
for (i = 0; i < std::min(formsCnt, entry->GetNumberOfTranslations()); i++)
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);
1681
// fill in remaining unset values:
1682
for (; i < formsCnt; i++)
1683
m_edittedTextOrig.push_back(_T(""));
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);
1695
1844
if (m_displayCommentWin)
1852
1997
wxMenuBar *menubar = GetMenuBar();
1853
1998
wxToolBar *toolbar = GetToolBar();
1855
if (m_catalog == NULL)
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);
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);
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);
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);
2017
menubar->EnableTop(2, editable);
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);
2026
menubar->Enable(XRCID("menu_purge_deleted"),
2027
editable && m_catalog->HasDeletedItems());
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);
1895
2034
#ifdef __WXGTK__
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);
1903
menubar->EnableTop(4, m_catalog != NULL);
2044
menubar->EnableTop(4, editable);
1904
2045
for (int i = 0; i < 10; i++)
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 &&
1909
2050
m_catalog->GetBookmarkIndex(Bookmark(i)) != -1);
1959
2100
void PoeditFrame::OnEditComment(wxCommandEvent& event)
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") );
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)
1968
2109
m_modified = true;
1970
2111
comment = dlg.GetComment();
1971
(*m_catalog)[selItem].SetComment(comment);
2112
entry->SetComment(comment);
1973
m_list->RefreshItem(m_sel);
2114
RefreshSelectedItem();
1975
2116
// update comment window
1976
2117
m_textComment->SetValue(CommentDialog::RemoveStartHash(comment));