1 /*
2 * Copyright 2005-2007 Gerald Schmidt.
3 *
4 * This file is part of Xml Copy Editor.
5 *
6 * Xml Copy Editor is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * Xml Copy Editor is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Xml Copy Editor; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <wx/intl.h>
22 #ifdef USE_ENCHANT
23 # include <enchant.h>
24 #else
25 # include "aspell.h"
26 #endif
27 #include "styledialog.h"
28 #include "nocasecompare.h"
29
30 BEGIN_EVENT_TABLE ( StyleDialog, wxDialog )
31 EVT_BUTTON ( ID_STYLE_REPORT, StyleDialog::OnReport )
32 EVT_BUTTON ( ID_STYLE_IGNORE_ALL, StyleDialog::OnStyleIgnoreAll )
33 EVT_BUTTON ( ID_STYLE_CHANGE_ALL, StyleDialog::OnStyleChangeAll )
34 EVT_BUTTON ( ID_STYLE_EDIT, StyleDialog::OnStyleEdit )
35 EVT_BUTTON ( ID_STYLE_WEB_REPORT, StyleDialog::OnStyleWebReport )
36 EVT_BUTTON ( ID_STYLE_WEB_SUMMARY, StyleDialog::OnStyleWebSummary )
37 EVT_BUTTON ( wxID_CANCEL, StyleDialog::OnCancel )
38 EVT_MENU ( ID_MENU_CHANGE_ONCE, StyleDialog::OnMenuChangeOnce )
39 EVT_MENU ( ID_MENU_CHANGE_ALL, StyleDialog::OnMenuChangeAll )
40 EVT_MENU ( ID_MENU_IGNORE_ONCE, StyleDialog::OnMenuIgnoreOnce )
41 EVT_MENU ( ID_MENU_IGNORE_ALL, StyleDialog::OnMenuIgnoreAll )
42 EVT_MENU ( ID_MENU_NEW_SUGGESTION, StyleDialog::OnMenuNewSuggestion )
43 EVT_MENU ( ID_MENU_APPLY_SUGGESTION_ALL, StyleDialog::OnMenuApplySuggestionAll )
44 EVT_LIST_COL_CLICK ( ID_STYLE_TABLE, StyleDialog::OnColumnClick )
45 EVT_LIST_ITEM_ACTIVATED ( ID_STYLE_TABLE, StyleDialog::OnItemActivated )
46 EVT_LIST_ITEM_RIGHT_CLICK ( ID_STYLE_TABLE, StyleDialog::OnItemRightClick )
47 EVT_UPDATE_UI_RANGE ( ID_STYLE_EDIT, ID_STYLE_CHANGE_ALL, StyleDialog::OnUpdateTableRange )
48 END_EVENT_TABLE()
49
50 #ifdef USE_ENCHANT
51 class dictdetect
52 {
53 public:
dictdetect(wxComboBox * aCombo)54 dictdetect(wxComboBox *aCombo) : ruleSetCombo(aCombo), anyFound(false) {}
55 void add(const char *lang_tag);
empty() const56 bool empty() const { return !anyFound; }
57 private:
58 wxComboBox *ruleSetCombo;
59 bool anyFound;
60 };
61
add(const char * lang_tag)62 void dictdetect::add(const char *lang_tag)
63 {
64 anyFound = true;
65 std::string stdEntry = lang_tag;
66 wxString entry = wxString ( stdEntry.c_str(), wxConvUTF8, stdEntry.size() );
67 ruleSetCombo->Append ( entry );
68 }
69
EnchantDictDescribe(const char * const lang_tag,const char * const provider_name,const char * const provider_desc,const char * const provider_file,void * user_data)70 void EnchantDictDescribe(const char * const lang_tag,
71 const char * const provider_name,
72 const char * const provider_desc,
73 const char * const provider_file,
74 void * user_data)
75 {
76 dictdetect *detected = (dictdetect*)user_data;
77 detected->add(lang_tag);
78 }
79
80 #endif
81
StyleDialog(wxWindow * parent,wxIcon icon,const std::string & bufferParameterUtf8,const wxString & fileNameParameter,const wxString & ruleSetDirectoryParameter,const wxString & filterDirectoryParameter,const wxString & ruleSetPresetParameter,const wxString & filterPresetParameter,const wxString & aspellDataPathParameter,const wxString & aspellDictPathParameter,int typeParameter,bool readOnlyParameter,wxPoint position,wxSize size)82 StyleDialog::StyleDialog (
83 wxWindow *parent,
84 wxIcon icon,
85 const std::string& bufferParameterUtf8,
86 const wxString& fileNameParameter,
87 const wxString& ruleSetDirectoryParameter,
88 const wxString& filterDirectoryParameter,
89 const wxString& ruleSetPresetParameter,
90 const wxString& filterPresetParameter,
91 #if !defined(USE_ENCHANT) && defined(__WXMSW__)
92 const wxString& aspellDataPathParameter,
93 const wxString& aspellDictPathParameter,
94 #endif
95 int typeParameter,
96 bool readOnlyParameter,
97 wxPoint position,
98 wxSize size )
99 : wxDialog (
100 parent,
101 wxID_ANY,
102 wxString ( ( typeParameter == ID_TYPE_STYLE) ? _ ( "Style" ) : _ ( "Spelling" ) ),
103 position,
104 size,
105 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX ),
106 indexForContextMenu ( -1 ),
107 bufferUtf8 ( bufferParameterUtf8 ),
108 #if !defined(USE_ENCHANT) && defined(__WXMSW__)
109 aspellDataPath ( aspellDataPathParameter ),
110 aspellDictPath ( aspellDictPathParameter ),
111 #endif
112 fileName ( fileNameParameter ),
113 ruleSetDirectory ( ruleSetDirectoryParameter ),
114 filterDirectory ( filterDirectoryParameter ),
115 ruleSetPreset ( ruleSetPresetParameter ),
116 filterPreset ( filterPresetParameter ),
117 type(typeParameter),
118 readOnly ( readOnlyParameter )
119 {
120 SetIcon ( icon );
121
122
123 // top box
124 ruleSetCombo = new wxComboBox (
125 this,
126 ID_STYLE_COMBO_RULESET,
127 _T ( "" ),
128 wxDefaultPosition,
129 wxSize ( 200, -1 )
130 );
131
132 int width, height;
133 ruleSetCombo->GetSize ( &width, &height );
134 wxSize buttonSize ( 100, height );
135
136 filterCombo = new wxComboBox (
137 this,
138 ID_STYLE_COMBO_FILTER,
139 _T ( "" ),
140 wxDefaultPosition,
141 wxSize ( 200, -1 ) );
142 //if (type != ID_TYPE_STYLE) // from v. 1.1.0.7: never show
143 filterCombo->Show ( false );
144
145 wxButton *createReportButton = new wxButton (
146 this,
147 ID_STYLE_REPORT,
148 _ ( "&Check" ),
149 wxDefaultPosition,
150 buttonSize,
151 0 );
152
153 wxBoxSizer *comboSizer = new wxBoxSizer ( wxHORIZONTAL );
154 comboSizer->Add ( ruleSetCombo, 0, wxRIGHT, 10 );
155 comboSizer->Add ( filterCombo, 0, wxRIGHT, 10 );
156 comboSizer->Add ( createReportButton, 0, wxRIGHT, 10 );
157
158 // middle box
159 wxListCtrl *myTable = new wxListCtrl (
160 this,
161 ID_STYLE_TABLE,
162 wxPoint ( 0, 0 ),
163 wxSize ( -1, -1 ),
164 wxLC_REPORT );
165 int widthUnit = 35;
166 myTable->InsertColumn ( 0, _ ( "No." ), wxLIST_FORMAT_LEFT, widthUnit * 1 );
167 myTable->InsertColumn ( 1, _ ( "Context" ), wxLIST_FORMAT_RIGHT, widthUnit * 3 );
168 myTable->InsertColumn ( 2, _ ( "Error" ), wxLIST_FORMAT_CENTER, widthUnit * 3 );
169 myTable->InsertColumn ( 3, _ ( "Context" ), wxLIST_FORMAT_LEFT, widthUnit * 3 );
170 myTable->InsertColumn ( 4, _ ( "Suggestion" ), wxLIST_FORMAT_LEFT, widthUnit * 3 );
171
172 myTable->InsertColumn ( 5, _ ( "Rule" ), wxLIST_FORMAT_LEFT, widthUnit * 3 );
173 myTable->InsertColumn ( 6, _ ( "Action" ), wxLIST_FORMAT_LEFT, widthUnit * 3 );
174 table = myTable;
175
176 // lower box
177 wxButton *editItemsButton =
178 new wxButton (
179 this,
180 ID_STYLE_EDIT,
181 _ ( "&Apply changes" ),
182 wxDefaultPosition,
183 wxSize ( -1, buttonSize.GetHeight() ),
184 0 );
185 wxButton *webReportButton =
186 new wxButton (
187 this,
188 ID_STYLE_WEB_REPORT,
189 _ ( "&Printable report" ),
190 wxDefaultPosition,
191 wxSize ( -1, buttonSize.GetHeight() ),
192 0 );
193 wxButton *webSummaryButton =
194 new wxButton (
195 this,
196 ID_STYLE_WEB_SUMMARY,
197 _ ( "Pr&intable summary" ),
198 wxDefaultPosition,
199 wxSize ( -1, buttonSize.GetHeight() ),
200 0 );
201 wxButton *selectAllButton =
202 new wxButton (
203 this,
204 ID_STYLE_CHANGE_ALL,
205 _ ( "C&hange all" ),
206 wxDefaultPosition,
207 wxSize ( -1, buttonSize.GetHeight() ),
208 0 );
209 wxButton *deselectAllButton =
210 new wxButton (
211 this,
212 ID_STYLE_IGNORE_ALL,
213 _ ( "I&gnore all" ),
214 wxDefaultPosition,
215 wxSize ( -1, buttonSize.GetHeight() ),
216 0 );
217 wxButton *cancelButton =
218 new wxButton (
219 this,
220 wxID_CANCEL,
221 _ ( "Ca&ncel" ),
222 wxDefaultPosition,
223 wxSize ( -1, buttonSize.GetHeight() ),
224 0 );
225
226 wxBoxSizer *reportButtonSizer = new wxBoxSizer ( wxHORIZONTAL );
227 reportButtonSizer->Add ( editItemsButton, 0, wxRIGHT, 10 );
228 reportButtonSizer->Add ( webReportButton, 0, wxLEFT | wxRIGHT, 10 );
229 reportButtonSizer->Add ( webSummaryButton, 0, wxRIGHT, 10 );
230 reportButtonSizer->Add ( selectAllButton, 0, wxLEFT | wxRIGHT, 10 );
231 reportButtonSizer->Add ( deselectAllButton, 0, wxRIGHT, 10 );
232 reportButtonSizer->Add ( cancelButton, 0, wxLEFT, 10 );
233
234 // status bar
235 status = new wxStatusBar ( this, wxID_ANY );
236
237 // overall sizer
238 wxBoxSizer *reportTopSizer = new wxBoxSizer ( wxVERTICAL );
239 reportTopSizer->Add ( comboSizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
240 reportTopSizer->Add ( table, 1, wxEXPAND | wxALL, 5 );
241 reportTopSizer->Add ( reportButtonSizer, 0, wxALL, 5 );
242 reportTopSizer->Add ( status, 0, wxEXPAND | wxALL );
243 this->SetSizer ( reportTopSizer );
244
245 createReportButton->SetFocus();
246
247 if ( readOnly )
248 filterCombo->Enable ( false );
249
250 // keyboard shortcuts
251 wxAcceleratorEntry entries[7];
252 entries[0].Set ( wxACCEL_ALT, ( int ) 'C', ID_STYLE_REPORT );
253 entries[1].Set ( wxACCEL_ALT, ( int ) 'A', ID_STYLE_EDIT );
254 entries[2].Set ( wxACCEL_ALT, ( int ) 'W', ID_STYLE_WEB_REPORT );
255 entries[3].Set ( wxACCEL_ALT, ( int ) 'B', ID_STYLE_WEB_SUMMARY );
256 entries[4].Set ( wxACCEL_ALT, ( int ) 'H', ID_STYLE_CHANGE_ALL );
257 entries[5].Set ( wxACCEL_ALT, ( int ) 'I', ID_STYLE_IGNORE_ALL );
258 entries[6].Set ( wxACCEL_ALT, ( int ) 'N', wxID_CANCEL );
259
260 wxAcceleratorTable accel ( 7, entries );
261 this->SetAcceleratorTable ( accel );
262
263 // update combo lists
264
265 // special case spellcheck
266 if (type == ID_TYPE_SPELL)
267 {
268 #ifdef USE_ENCHANT
269 EnchantBroker *broker = enchant_broker_init();
270 dictdetect adetected(ruleSetCombo);
271 enchant_broker_list_dicts(broker, EnchantDictDescribe, &adetected);
272 bool anyFound = !adetected.empty();
273 #else
274 AspellConfig *config;
275 AspellDictInfoList *dlist;
276 AspellDictInfoEnumeration *dels;
277 const AspellDictInfo *entry;
278
279 config = new_aspell_config();
280
281 #ifdef __WXMSW__
282 aspell_config_replace ( config, "data-dir", aspellDataPath.mb_str() ); //ASPELL_DATA_PATH );
283 aspell_config_replace ( config, "dict-dir", aspellDictPath.mb_str() ); //ASPELL_DICT_PATH );
284 #endif
285 dlist = get_aspell_dict_info_list( config );
286
287 delete_aspell_config ( config );
288
289 dels = aspell_dict_info_list_elements ( dlist );
290
291 bool anyFound = false;
292 while ( ( entry = aspell_dict_info_enumeration_next ( dels ) ) != 0 )
293 {
294 anyFound = true;
295 std::string stdEntry = entry->name;
296 wxString entry = wxString ( stdEntry.c_str(), wxConvUTF8, stdEntry.size() );
297 ruleSetCombo->Append ( entry );
298 }
299 #endif
300
301 if ( anyFound )
302 {
303 if ( ruleSetPreset.empty() )
304 ruleSetPreset = _ ( "en_US" );
305 ruleSetCombo->SetValue ( ruleSetPreset );
306 }
307 else
308 {
309 ruleSetCombo->Append ( _ ( "(No dictionaries found)" ) );
310 ruleSetCombo->Select ( 0 );
311 createReportButton->Enable ( false );
312 }
313
314 return;
315 }
316
317 // all other branches
318 if ( wxDirExists ( ruleSetDirectory ) )
319 {
320 wxString ruleMask, ruleFile;
321 ruleMask = ruleSetDirectory + wxFileName::GetPathSeparator() + _T ( "*.xml" );
322 ruleFile = wxFindFirstFile ( ruleMask, wxFILE );
323
324 if ( !ruleFile.empty() )
325 {
326 ruleFile.Replace ( _T ( ".xml" ), _T ( "" ) );
327 ruleFile.Replace ( _T ( "_" ), _T ( " " ) );
328 ruleSetCombo->Append ( wxFileNameFromPath ( ruleFile ) );
329 for ( ;; )
330 {
331 ruleFile = wxFindNextFile();
332 if ( ruleFile.empty() )
333 break;
334 ruleFile.Replace ( _T ( ".xml" ), _T ( "" ) );
335 ruleFile.Replace ( _T ( "_" ), _T ( " " ) );
336 ruleSetCombo->Append ( wxFileNameFromPath ( ruleFile ) );
337 }
338 }
339 if ( ruleSetPreset.empty() )
340 ruleSetPreset = _ ( "Default" );
341 ruleSetCombo->SetValue ( ruleSetPreset );
342 }
343 else
344 {
345 ruleSetCombo->Append ( _ ( "(No rule sets found)" ) );
346 ruleSetCombo->Select ( 0 );
347 }
348
349 if ( wxDirExists ( filterDirectory ) )
350 {
351 filterCombo->Append ( _ ( "(No filter)" ) );
352 wxString filterMask, filterFile;
353 filterMask = filterDirectory + wxFileName::GetPathSeparator() + _T ( "*.xml" );
354
355 filterFile = wxFindFirstFile ( filterMask, wxFILE );
356
357 if ( !filterFile.empty() )
358 {
359 filterFile.Replace ( _T ( ".xml" ), _T ( "" ) );
360 filterCombo->Append ( wxFileNameFromPath ( filterFile ) );
361 for ( ;; )
362 {
363 filterFile = wxFindNextFile();
364 if ( filterFile.empty() )
365 break;
366 filterFile.Replace ( _T ( ".xml" ), _T ( "" ) );
367 filterCombo->Append ( wxFileNameFromPath ( filterFile ) );
368 }
369 }
370 filterCombo->SetValue ( filterPreset );
371 }
372 else
373 {
374 filterCombo->Append ( _ ( "(No filters found)" ) );
375 filterCombo->Select ( 0 );
376 }
377 }
378
~StyleDialog()379 StyleDialog::~StyleDialog()
380 {
381 std::set<wxString>::iterator it;
382 for ( it = tempFiles.begin(); it != tempFiles.end(); ++it )
383 wxRemoveFile ( *it );
384 }
385
OnColumnClick(wxListEvent & event)386 void StyleDialog::OnColumnClick ( wxListEvent& event )
387 {
388 boost::scoped_ptr<SortData> data ( new SortData );
389 data->column = event.GetColumn();
390 data->table = table;
391 table->SortItems ( MyCompareFunction, ( wxIntPtr ) data.get() );
392
393 long itemCount = table->GetItemCount();
394 for ( int i = 0; i < itemCount; ++i )
395 table->SetItemData ( i, i );
396 }
397
OnItemActivated(wxListEvent & event)398 void StyleDialog::OnItemActivated ( wxListEvent& event )
399 {
400 int index = event.GetIndex();
401 bool ignore = ( getTextByColumn ( table, index, 6 ) == _ ( "Ignore" ) );
402 setIgnore ( index, ( ignore ) ? false : true );
403 }
404
OnItemRightClick(wxListEvent & event)405 void StyleDialog::OnItemRightClick ( wxListEvent& event )
406 {
407 int index = indexForContextMenu = event.GetIndex();
408
409 wxString match, suggestion;
410 match = getTextByColumn ( table, index, 2 );
411 suggestion = getTextByColumn ( table, index, 4 );
412
413 wxMenu contextMenu;
414 contextMenu.Append (
415 ID_MENU_IGNORE_ONCE, _ ( "Ignore once" ) );
416 contextMenu.Append (
417 ID_MENU_IGNORE_ALL, _ ( "Ignore all" ) );
418 contextMenu.AppendSeparator();
419 contextMenu.Append ( ID_MENU_CHANGE_ONCE, _ ( "Change once" ) );
420 contextMenu.Append ( ID_MENU_CHANGE_ALL, _ ( "Change all" ) );
421 contextMenu.AppendSeparator();
422 contextMenu.Append (
423 ID_MENU_NEW_SUGGESTION, _ ( "New suggestion..." ) );
424
425 wxString menuString;
426 menuString.Printf ( _T ( "Change '%s' to '%s' throughout" ), match.c_str(), suggestion.c_str() );
427
428 contextMenu.Append (
429 ID_MENU_APPLY_SUGGESTION_ALL, menuString );
430
431 bool ignore = ( getTextByColumn ( table, index, 6 ) == _ ( "Ignore" ) );
432 contextMenu.Enable ( ( ignore ) ? ID_MENU_IGNORE_ONCE : ID_MENU_CHANGE_ONCE, false );
433 PopupMenu ( &contextMenu, wxPoint ( -1, -1 ) );
434 }
435
OnCancel(wxCommandEvent & event)436 void StyleDialog::OnCancel ( wxCommandEvent& event )
437 {
438 updateSizeInformation();
439 event.Skip();
440 }
441
OnReport(wxCommandEvent & event)442 void StyleDialog::OnReport ( wxCommandEvent& event )
443 {
444 table->DeleteAllItems();
445 matchVector.clear();
446 status->SetStatusText ( _ ( "Checking document..." ) );
447
448 // update presets
449 ruleSetPreset = ruleSetCombo->GetValue();
450 filterPreset = filterCombo->GetValue();
451
452 // reconstitute short filenames
453 wxString ruleSet, filter;
454 ruleSet = ruleSetPreset + _T ( ".xml" );
455 ruleSet.Replace ( _(" "), _T("_") );
456 filter = filterPreset + _T ( ".xml" );
457
458 wxString separator = wxFileName::GetPathSeparator();
459
460 boost::scoped_ptr<HouseStyle> hs ( new HouseStyle (
461 (type == ID_TYPE_SPELL) ? HS_TYPE_SPELL : HS_TYPE_STYLE,
462 bufferUtf8,
463 ruleSetDirectory,
464 ruleSet,
465 filterDirectory,
466 filter,
467 separator,
468 #ifdef __WXMSW__
469 aspellDataPath,
470 aspellDictPath,
471 #endif
472 5 ) );
473
474 status->SetStatusText ( _ ( "Checking document..." ) );
475 if ( !hs->createReport() )
476 {
477 const wxString &error = hs->getLastError();
478 status->SetStatusText ( _ ( "Cannot check document: " ) + error );
479 return;
480 }
481 matchVector = hs->getMatchVector();
482
483 vector<ContextMatch>::iterator it;
484 std::string prelogUtf8, matchUtf8, postlogUtf8, replaceUtf8, reportUtf8;
485 wxString matchNo, prelog, match, postlog, replace, report;
486 int i = 0;
487 for ( it = matchVector.begin(); it != matchVector.end(); ++it )
488 {
489 matchNo.Printf ( _T ( "%i" ), i + 1 ); // display numbers from 1
490 prelogUtf8 = flatWhiteSpace ( ( *it ).prelog );
491 matchUtf8 = flatWhiteSpace ( ( *it ).match );
492 postlogUtf8 = flatWhiteSpace ( ( *it ).postlog );
493 replaceUtf8 = flatWhiteSpace ( ( *it ).replace );
494 reportUtf8 = flatWhiteSpace ( ( *it ).report );
495 prelog = wxString ( prelogUtf8.c_str(), wxConvUTF8, ( *it ).prelog.size() );
496 match = wxString ( matchUtf8.c_str(), wxConvUTF8, ( *it ).match.size() );
497 postlog = wxString ( postlogUtf8.c_str(), wxConvUTF8, ( *it ).postlog.size() );
498 replace = wxString ( replaceUtf8.c_str(), wxConvUTF8, ( *it ).replace.size() );
499 report = wxString ( reportUtf8.c_str(), wxConvUTF8, ( *it ).report.size() );
500 table->InsertItem ( i, matchNo, 0 );
501 table->SetItem ( i, 1, prelog );
502 table->SetItem ( i, 2, match );
503 table->SetItem ( i, 3, postlog );
504 table->SetItem ( i, 4, replace );
505 table->SetItem ( i, 5, report );
506 setIgnore ( i, ( *it ).tentative );
507 table->SetItemData ( i, i );
508 ++i;
509 }
510 wxString message;
511 message.Printf ( wxPLURAL ( "%i error", "%i errors", i ), i );
512 status->SetStatusText ( message );
513 if ( i )
514 table->SetFocus();
515 }
516
OnStyleEdit(wxCommandEvent & event)517 void StyleDialog::OnStyleEdit ( wxCommandEvent& event )
518 {
519 updateSizeInformation();
520
521 std::vector<ContextMatch> v;
522 getSelectedMatches ( v );
523
524 if ( v.empty() )
525 {
526 status->SetStatusText ( _ ( "No items selected" ) );
527 return;
528 }
529
530 sort ( v.begin(), v.end(), elementAndOffsetCompareFunction );
531
532 /*
533 HouseStyleWriter hsw ( v );
534 if ( !hsw.parse ( bufferUtf8 ) )
535 {
536 std::string error = hsw.getLastError();
537 wxString wideError = wxString (
538 error.c_str(),
539 wxConvUTF8,
540 error.size() );
541
542 status->SetStatusText ( wideError );
543 return;
544 }
545 bufferUtf8 = hsw.getOutput();
546 */
547
548
549 //unsigned elementCount = 1; // from v. 1.1.0.7: one raw text element only
550 int vectorsize, os_adjust, exclusion;
551
552 vectorsize = v.size();
553 os_adjust = exclusion = 0;
554 string cmp1, cmp2, buffer;
555 buffer = bufferUtf8;
556
557 for ( int i = 0; i < vectorsize; ++i )
558 {
559 /*
560 unsigned vectorElementCount = v[i].elementCount;
561 if ( vectorElementCount < elementCount )
562 continue;
563 else if ( vectorElementCount > elementCount )
564 break;
565 else if ( vectorElementCount == elementCount )
566 {
567 */
568 int offset = ( int ) v[i].offset + os_adjust;
569
570 if ( offset < exclusion )
571 continue;
572
573 try
574 {
575 cmp1 = v[i].match;
576 cmp2 = buffer.substr ( offset, v[i].match.size() );
577 }
578 catch ( std::exception& e )
579 {
580 continue;
581 }
582
583 if ( cmp1.compare ( cmp2 ) )
584 continue;
585
586 buffer.replace ( offset, v[i].match.size(), v[i].replace.c_str() );
587
588 os_adjust += v[i].replace.size() - v[i].match.size();
589 exclusion = offset + v[i].replace.size();
590
591 //}
592
593 }
594 bufferUtf8 = buffer;
595
596 wxCommandEvent e;
597 EndModal ( wxID_OK );
598 }
599
getEditedString()600 std::string StyleDialog::getEditedString()
601 {
602 return bufferUtf8;
603 }
604
OnStyleIgnoreAll(wxCommandEvent & event)605 void StyleDialog::OnStyleIgnoreAll ( wxCommandEvent& event )
606 {
607 styleSetIgnoreAll ( true );
608 }
609
OnStyleChangeAll(wxCommandEvent & event)610 void StyleDialog::OnStyleChangeAll ( wxCommandEvent& event )
611 {
612 styleSetIgnoreAll ( false );
613 }
614
OnStyleWebReport(wxCommandEvent & event)615 void StyleDialog::OnStyleWebReport ( wxCommandEvent& event )
616 {
617 std::vector<ContextMatch> v;
618 getAllMatches ( v );
619
620 sort ( v.begin(), v.end(), reportCompareFunction );
621
622 // temporary file should be in default temporary folder
623 wxString tempNameWide = wxFileName::CreateTempFileName ( _T ( "" ) );
624 if ( tempNameWide.empty() )
625 return;
626 tempNameWide.Replace ( _T ( ".tmp" ), _T ( "_report.html" ), true );
627 tempFiles.insert ( tempNameWide );
628 std::string tempNameUtf8 = ( const char * ) tempNameWide.mb_str ( wxConvUTF8 );
629 std::ofstream ofs ( tempNameUtf8.c_str() );
630 if ( !ofs )
631 return;
632
633 WrapExpat we;
634
635 ofs << XHTML_START;
636 ofs << "<body><h2>";
637 ofs << fileName.mb_str ( wxConvUTF8 );
638 ofs << "</h2><table><tr>";
639 ofs << "<td><b align=\"right\">No.</b></td>";
640 ofs << "<td align=\"right\"><b>Context</b></td>";
641 ofs << "<td align=\"center\"><b>Match</b></td>";
642 ofs << "<td align=\"left\"><b>Context</b></td>";
643 ofs << "<td><b>Suggestion</b></td><td><b>Report</b></td></tr>";
644 std::vector<ContextMatch>::iterator it;
645 int matchCount = 0;
646 for ( it = v.begin(); it != v.end(); ++it )
647 {
648 ofs << "<tr><td align=\"right\">";
649 ofs << ++matchCount;
650 ofs << "</td>";
651 ofs << "<td align=\"right\">";
652 ofs << we.xmliseTextNode ( it->prelog );
653 ofs << "</td><td align=\"center\"><font color=\"red\"><b>";
654 ofs << we.xmliseTextNode ( it->match );
655 ofs << "</b></font></td><td align=\"left\">";
656 ofs << we.xmliseTextNode ( it->postlog );
657 ofs << "</td><td><font color=\"green\"><b>";
658 ofs << we.xmliseTextNode ( it->replace );
659 ofs << "</b></font></td><td>";
660 ofs << we.xmliseTextNode ( it->report );
661 ofs << "</td></tr>";
662 }
663 ofs << "</table></body>";
664 ofs << XHTML_END;
665 ofs.close();
666
667 // display file in browser
668 if ( !wxFileExists ( tempNameWide ) )
669 return;
670
671 wxLaunchDefaultBrowser ( tempNameWide );
672 }
673
OnStyleWebSummary(wxCommandEvent & event)674 void StyleDialog::OnStyleWebSummary ( wxCommandEvent& event )
675 {
676 std::vector<ContextMatch> v;
677 getAllMatches ( v );
678
679 std::map<std::string, int, NoCaseCompare> matchMap;
680 std::vector<ContextMatch>::iterator vectorIterator;
681 for (
682 vectorIterator = v.begin();
683 vectorIterator != v.end();
684 ++vectorIterator )
685 {
686 if ( ( matchMap.find ( vectorIterator->match ) ) != matchMap.end() )
687 ++ ( matchMap[vectorIterator->match] );
688 else
689 matchMap[vectorIterator->match] = 1;
690 }
691
692 // temporary file should be in default temporary folder
693 wxString tempNameWide = wxFileName::CreateTempFileName ( _T ( "" ) );
694 if ( tempNameWide.empty() )
695 return;
696 tempNameWide.Replace ( _T ( ".tmp" ), _T ( "_summary.html" ), true );
697 tempFiles.insert ( tempNameWide );
698 std::string tempNameUtf8 = ( const char * ) tempNameWide.mb_str ( wxConvUTF8 );
699 std::ofstream ofs ( tempNameUtf8.c_str() );
700 if ( !ofs )
701 return;
702 ofs << XHTML_START;
703 ofs << "<body><h2>";
704 ofs << fileName.mb_str ( wxConvUTF8 );
705 ofs << "</h2>";
706
707 WrapExpat we;
708 ofs << "<table><tr><th>Term</th><th>Frequency</th></tr>";
709 std::map<std::string, int>::iterator mapIterator;
710 int matchTotal = 0;
711
712 for (
713 mapIterator = matchMap.begin();
714 mapIterator != matchMap.end();
715 ++mapIterator )
716 {
717 ofs << "<tr><td>";
718 ofs << we.xmliseTextNode ( mapIterator->first );
719 ofs << "</td><td>";
720
721 // handle number of matches
722 matchTotal += mapIterator->second;
723 ofs << mapIterator->second;
724 ofs << "</td></tr>";
725 }
726 ofs << "<tr><th>Total</th><th>";
727 ofs << matchTotal;
728 ofs << "</th></tr></table></body>";
729 ofs << XHTML_END;
730
731 ofs.close();
732
733 // display file in browser
734 if ( !wxFileExists ( tempNameWide ) )
735 return;
736
737 wxLaunchDefaultBrowser ( tempNameWide );
738 }
739
styleSetIgnoreAll(bool ignore)740 void StyleDialog::styleSetIgnoreAll ( bool ignore )
741 {
742 int count = table->GetItemCount();
743 for ( int i = 0; i < count; ++i )
744 setIgnore ( i, ignore );
745 }
746
isIgnore(int item)747 bool StyleDialog::isIgnore ( int item )
748 {
749 wxString field = getTextByColumn ( table, item, 6 );
750 return ( field == _ ( "Ignore" ) ) ? true : false;
751 }
752
setIgnore(int item,bool ignore)753 void StyleDialog::setIgnore ( int item, bool ignore )
754 {
755 table->SetItem ( item, 6, ( ignore ) ? _ ( "Ignore" ) : _ ( "Change" ) );
756 table->SetItemTextColour ( item, ( ignore ) ? *wxBLUE : *wxBLACK );
757 }
758
getAllMatches(vector<ContextMatch> & v)759 void StyleDialog::getAllMatches ( vector<ContextMatch> &v )
760 {
761 v.clear();
762 int count = table->GetItemCount();
763 wxString matchNoString;
764 long matchNo;
765 for ( int i = 0; i < count; ++i )
766 {
767 matchNoString = table->GetItemText ( i );
768 if ( !matchNoString.ToLong ( &matchNo ) || matchNo < 1 )
769 continue;
770 v.push_back ( matchVector.at ( matchNo - 1 ) ); // vector index starts at 0
771 }
772 }
773
getSelectedMatches(vector<ContextMatch> & v)774 void StyleDialog::getSelectedMatches ( vector<ContextMatch> &v )
775 {
776 v.clear();
777 int count = table->GetItemCount();
778 wxString selectionString, matchNoString;
779 long matchNo;
780 for ( int i = 0; i < count; ++i )
781 {
782 selectionString = getTextByColumn ( table, i, 6 );
783 if ( selectionString != _ ( "Change" ) )
784 continue;
785 matchNoString = table->GetItemText ( i );
786 if ( !matchNoString.ToLong ( &matchNo ) || matchNo < 1 )
787 continue;
788 v.push_back ( matchVector.at ( matchNo - 1 ) ); // vector index starts at 0
789 }
790 }
791
MyCompareFunction(wxIntPtr item1,wxIntPtr item2,wxIntPtr sortData)792 int wxCALLBACK StyleDialog::MyCompareFunction (
793 #if wxCHECK_VERSION(2,9,0) || defined (_WIN64) || defined (__x86_64__)
794 wxIntPtr item1,
795 wxIntPtr item2,
796 wxIntPtr sortData )
797 #else
798 long item1,
799 long item2,
800 long sortData )
801 #endif
802 {
803 SortData *data = ( SortData * ) sortData;
804 int column;
805 wxListCtrl *table;
806 column = data->column;
807 table = data->table;
808
809 wxString string1 = getTextByColumn ( table, item1, column );
810 wxString string2 = getTextByColumn ( table, item2, column );
811
812 // special case: numerical content
813 if ( string1.IsNumber() && string2.IsNumber() )
814 {
815 long value1, value2;
816 string1.ToLong ( &value1 );
817 string2.ToLong ( &value2 );
818 if ( value1 < value2 )
819 return -1;
820 else if ( value1 > value2 )
821 return 1;
822 else
823 return 0;
824 }
825
826 if ( string1.CmpNoCase ( string2 ) < 0 )
827 return -1;
828 else if ( string1.CmpNoCase ( string2 ) > 0 )
829 return 1;
830 else
831 return 0;
832 }
833
elementAndOffsetCompareFunction(ContextMatch m1,ContextMatch m2)834 bool StyleDialog::elementAndOffsetCompareFunction (
835 ContextMatch m1,
836 ContextMatch m2 )
837 {
838 if ( m1.elementCount == m2.elementCount )
839 return ( m1.offset < m2.offset );
840 return ( m1.elementCount < m2.elementCount );
841 }
842
reportCompareFunction(ContextMatch m1,ContextMatch m2)843 bool StyleDialog::reportCompareFunction ( ContextMatch m1, ContextMatch m2 )
844 {
845 return ( m1.report < m2.report );
846 }
847
getTextByColumn(wxListCtrl * table,long index,int col)848 wxString StyleDialog::getTextByColumn ( wxListCtrl *table, long index, int col )
849 {
850 wxListItem Item;
851 Item.SetId ( index );
852 Item.SetColumn ( col );
853 Item.SetMask ( wxLIST_MASK_TEXT );
854 table->GetItem ( Item );
855 return Item.GetText();
856 }
857
OnUpdateTableRange(wxUpdateUIEvent & event)858 void StyleDialog::OnUpdateTableRange ( wxUpdateUIEvent& event )
859 {
860 if ( event.GetId() == ID_STYLE_EDIT && readOnly )
861 {
862 event.Enable ( false );
863 return;
864 }
865 event.Enable ( table->GetItemCount() );
866 }
867
OnMenuChangeOnce(wxCommandEvent & event)868 void StyleDialog::OnMenuChangeOnce ( wxCommandEvent& event )
869 {
870 setIgnore ( indexForContextMenu, false );
871 }
872
OnMenuChangeAll(wxCommandEvent & event)873 void StyleDialog::OnMenuChangeAll ( wxCommandEvent& event )
874 {
875 wxString match, suggestion;
876 match = getTextByColumn ( table, indexForContextMenu, 2 );
877 suggestion = getTextByColumn ( table, indexForContextMenu, 4 );
878
879 long itemCount = table->GetItemCount();
880 for ( int i = 0; i < itemCount; ++i )
881 {
882 if ( getTextByColumn ( table, i, 2 ) == match )
883 setIgnore ( i, false );
884 }
885 }
886
OnMenuIgnoreOnce(wxCommandEvent & event)887 void StyleDialog::OnMenuIgnoreOnce ( wxCommandEvent& event )
888 {
889 setIgnore ( indexForContextMenu, true );
890 }
891
OnMenuIgnoreAll(wxCommandEvent & event)892 void StyleDialog::OnMenuIgnoreAll ( wxCommandEvent& event )
893 {
894 wxString match, suggestion;
895 match = getTextByColumn ( table, indexForContextMenu, 2 );
896 suggestion = getTextByColumn ( table, indexForContextMenu, 4 );
897
898 long itemCount = table->GetItemCount();
899 for ( int i = 0; i < itemCount; ++i )
900 {
901 if ( getTextByColumn ( table, i, 2 ) == match )
902 {
903 table->SetItem ( i, 4, suggestion );
904 setIgnore ( i, true );
905 }
906 }
907 }
908
OnMenuNewSuggestion(wxCommandEvent & event)909 void StyleDialog::OnMenuNewSuggestion ( wxCommandEvent& event )
910 {
911 wxString suggestion = getTextByColumn ( table, indexForContextMenu, 4 );
912 wxTextEntryDialog *dlg = new wxTextEntryDialog (
913 this,
914 _ ( "Enter new suggestion:" ),
915 _ ( "New Suggestion" ),
916 suggestion );
917 if ( !dlg )
918 return;
919
920 int ret = dlg->ShowModal();
921 if ( ret == wxID_CANCEL )
922 return;
923
924 // identify item in match vector
925 wxString noString = getTextByColumn ( table, indexForContextMenu, 0 );
926 long no;
927 if ( !noString.ToLong ( &no ) || no < 1 || no > ( long ) matchVector.size() )
928 return;
929 --no; // reverse display offset
930
931 wxString wideReplace = dlg->GetValue();
932 std::string replace = ( const char * ) wideReplace.mb_str ( wxConvUTF8 );
933 matchVector[no].replace = replace;
934 table->SetItem ( indexForContextMenu, 4, dlg->GetValue() );
935 setIgnore ( indexForContextMenu, false );
936 }
937
OnMenuApplySuggestionAll(wxCommandEvent & event)938 void StyleDialog::OnMenuApplySuggestionAll ( wxCommandEvent& event )
939 {
940 wxString match, suggestion;
941 match = getTextByColumn ( table, indexForContextMenu, 2 );
942 suggestion = getTextByColumn ( table, indexForContextMenu, 4 );
943
944 long itemCount = table->GetItemCount();
945 for ( int i = 0; i < itemCount; ++i )
946 {
947 if ( getTextByColumn ( table, i, 2 ) != match )
948 continue;
949
950 // identify item in match vector
951 wxString noString = getTextByColumn ( table, i, 0 );
952 long no;
953 if ( !noString.ToLong ( &no ) || no < 1 || no > ( long ) matchVector.size() )
954 continue;
955 --no; // reverse display offset
956
957 std::string replace = ( const char * ) suggestion.mb_str ( wxConvUTF8 );
958 matchVector[no].replace = replace;
959 table->SetItem ( i, 4, suggestion );
960 setIgnore ( i, false );
961 }
962 }
963
flatWhiteSpace(std::string & s)964 std::string StyleDialog::flatWhiteSpace ( std::string& s )
965 {
966 std::string::iterator it;
967 std::string output;
968 output.reserve ( s.size() );
969 for ( it = s.begin(); it != s.end(); ++it )
970 {
971 if ( *it == '\t' || *it == '\r' || *it == '\n' )
972 output += ' ';
973 else
974 output += *it;
975 }
976 return output;
977 }
978
updateSizeInformation()979 void StyleDialog::updateSizeInformation()
980 {
981 framePosition = GetPosition();
982 frameSize = GetSize();
983 }
984
getPosition()985 wxPoint StyleDialog::getPosition()
986 {
987 return framePosition;
988 }
989
getSize()990 wxSize StyleDialog::getSize()
991 {
992 return frameSize;
993 }
994