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 "xmlctrl.h"
22 #include "xmlpromptgenerator.h"
23 #include "xmlshallowvalidator.h"
24 #include "xmlencodinghandler.h"
25 //#include "wrapxerces.h"
26 #include "xmlcopyeditor.h" // needed to enable validation-as-you-type alerts
27 #include <utility>
28 #include <memory>
29 #include "validationthread.h"
30
31
32 // adapted from wxSTEdit (c) 2005 John Labenski, Otto Wyss
33 #define XMLCTRL_HASBIT(value, bit) (((value) & (bit)) != 0)
34
35 BEGIN_EVENT_TABLE ( XmlCtrl, wxStyledTextCtrl )
36 EVT_CHAR ( XmlCtrl::OnChar )
37 EVT_KEY_DOWN ( XmlCtrl::OnKeyPressed )
38 EVT_IDLE ( XmlCtrl::OnIdle )
39 EVT_STC_MARGINCLICK ( wxID_ANY, XmlCtrl::OnMarginClick )
40 EVT_LEFT_DOWN ( XmlCtrl::OnMouseLeftDown )
41 EVT_LEFT_UP ( XmlCtrl::OnMouseLeftUp )
42 EVT_RIGHT_UP ( XmlCtrl::OnMouseRightUp )
43 EVT_MIDDLE_DOWN ( XmlCtrl::OnMiddleDown )
44 EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_VALIDATION_COMPLETED, XmlCtrl::OnValidationCompleted)
45 EVT_NOTIFY ( myEVT_NOTIFY_PROMPT_GENERATED, wxID_ANY, XmlCtrl::OnPromptGenerated )
46 EVT_KILL_FOCUS ( XmlCtrl::OnKillFocus )
47 END_EVENT_TABLE()
48
49 // global protection for validation threads
50 wxCriticalSection xmlcopyeditorCriticalSection;
51
XmlCtrl(wxWindow * parent,const XmlCtrlProperties & propertiesParameter,bool * protectTagsParameter,int visibilityStateParameter,int typeParameter,wxWindowID id,const char * buffer,size_t bufferLen,const wxString & basePathParameter,const wxString & auxPathParameter,const wxPoint & position,const wxSize & size,long style)52 XmlCtrl::XmlCtrl (
53 wxWindow *parent,
54 const XmlCtrlProperties &propertiesParameter,
55 bool *protectTagsParameter,
56 int visibilityStateParameter,
57 int typeParameter,
58 wxWindowID id,
59 const char *buffer, // could be NULL
60 size_t bufferLen,
61 const wxString& basePathParameter,
62 const wxString& auxPathParameter,
63 const wxPoint& position,
64 const wxSize& size,
65 long style
66 )
67 : wxStyledTextCtrl ( parent, id, position, size, style )
68 , type ( typeParameter )
69 , protectTags ( protectTagsParameter )
70 , visibilityState ( visibilityStateParameter )
71 , basePath ( basePathParameter )
72 , auxPath ( auxPathParameter )
73 {
74 validationThread = NULL;
75 mPromptGeneratorThread = NULL;
76
77 grammarFound = false;
78 validationRequired = (buffer) ? true : false; // NULL for plain XML template
79
80 currentMaxLine = 1;
81
82 applyProperties ( propertiesParameter );
83
84 SetTabWidth ( 2 );
85 SetWrapStartIndent ( 2 );
86 SetWrapVisualFlags ( wxSTC_WRAPVISUALFLAG_START );
87 SetUseTabs ( false );
88 SetBackSpaceUnIndents ( true );
89 SetTabIndents ( false );
90 SetUndoCollection ( false );
91
92 // handle NULL buffer
93 if ( !buffer )
94 {
95 buffer = DEFAULT_XML_DECLARATION_UTF8;
96 bufferLen = strlen ( DEFAULT_XML_DECLARATION_UTF8 );
97 }
98
99 #if wxCHECK_VERSION(2,9,0)
100 if ( type != FILE_TYPE_BINARY )
101 SetScrollWidthTracking ( true );
102 #endif
103
104 #if wxCHECK_VERSION(2,9,0)
105 AddTextRaw ( buffer, bufferLen );
106 #else
107 SendMsg ( 2001, bufferLen, ( wxIntPtr ) buffer );
108 #endif
109
110 SetSelection ( 0, 0 );
111
112 // position cursor
113 if ( type == FILE_TYPE_XML &&
114 bufferLen > 5 &&
115 buffer[0] == '<' &&
116 buffer[1] == '?' &&
117 buffer[2] == 'x' &&
118 buffer[3] == 'm' &&
119 buffer[4] == 'l' &&
120 GetLineCount() > 1 )
121 {
122 GotoLine ( 1 ); // == line 2 of the document
123 }
124
125
126 SetSavePoint();
127 SetUndoCollection ( true );
128 AutoCompSetSeparator ( '<' );
129
130 applyVisibilityState ( visibilityState );
131 lineBackgroundState = BACKGROUND_STATE_NORMAL;
132
133 for ( int i = 0; i < wxSTC_INDIC_MAX; ++i )
134 IndicatorSetStyle ( i, wxSTC_INDIC_HIDDEN );
135 IndicatorSetStyle ( 2, wxSTC_INDIC_SQUIGGLE );
136 IndicatorSetForeground ( 2, *wxRED );
137 #if wxCHECK_VERSION(2,9,0)
138 SetIndicatorCurrent ( 2 );
139 #endif
140 }
141
142
~XmlCtrl()143 XmlCtrl::~XmlCtrl()
144 {
145 attributeMap.clear();
146 elementMap.clear();
147 entitySet.clear();
148
149 if ( validationThread != NULL )
150 {
151 validationThread->PendingDelete();
152 //validationThread->Delete();
153 //delete validationThread;
154 }
155 if ( mPromptGeneratorThread != NULL )
156 mPromptGeneratorThread->PendingDelete();
157 }
158
159
160 // taken from wxStyledNotebook (c) Eran Ifrah <eranif@bezeqint.net>
LightColour(const wxColour & color,int percent)161 static wxColor LightColour ( const wxColour& color, int percent )
162 {
163 int rd, gd, bd, high = 0;
164 wxColor end_color = wxT ( "WHITE" );
165 rd = end_color.Red() - color.Red();
166 gd = end_color.Green() - color.Green();
167 bd = end_color.Blue() - color.Blue();
168 high = 100;
169
170 // We take the percent way of the color from color --> white
171 int i = percent;
172 int r = color.Red() + ( ( i*rd*100 ) /high ) /100;
173 int g = color.Green() + ( ( i*gd*100 ) /high ) /100;
174 int b = color.Blue() + ( ( i*bd*100 ) /high ) /100;
175 return wxColor ( r, g, b );
176 }
177
OnIdle(wxIdleEvent & event)178 void XmlCtrl::OnIdle ( wxIdleEvent& event )
179 {
180 if ( properties.number && type != FILE_TYPE_BINARY )
181 adjustNoColumnWidth(); // exits if unchanged
182 }
183
OnValidationCompleted(wxCommandEvent & event)184 void XmlCtrl::OnValidationCompleted ( wxCommandEvent &event )
185 {
186 wxCriticalSectionLocker locker ( xmlcopyeditorCriticalSection );
187
188 if ( validationThread == NULL )
189 return;
190
191 MyFrame *frame = (MyFrame *)GetGrandParent();
192 clearErrorIndicators ( GetLineCount() );
193 if ( validationThread->isSucceeded() )
194 {
195 frame->statusProgress ( wxEmptyString );
196 }
197 else
198 {
199 setErrorIndicator ( validationThread->getPosition().first - 1, 0 );
200 frame->statusProgress ( validationThread->getMessage() );
201 }
202
203 validationThread->Wait();
204 delete validationThread;
205 validationThread = NULL;
206 }
207
OnChar(wxKeyEvent & event)208 void XmlCtrl::OnChar ( wxKeyEvent& event )
209 {
210 if ( *protectTags )
211 {
212 SetOvertype ( false );
213 if ( GetSelectionStart() != GetSelectionEnd() )
214 adjustSelection();
215 if ( !canInsertAt ( GetCurrentPos() ) )
216 adjustPosRight();
217 }
218
219 if ( ( !properties.completion || GetOvertype() ) &&
220 !*protectTags )
221 {
222 event.Skip();
223 return;
224 }
225
226 switch ( event.GetKeyCode() )
227 {
228 case '<':
229 handleOpenAngleBracket ( event );
230 return;
231 case '>':
232 handleCloseAngleBracket ( event );
233 return;
234 case ' ':
235 handleSpace ( event );
236 return;
237 case '=':
238 handleEquals ( event );
239 return;
240 case '&':
241 handleAmpersand ( event );
242 return;
243 case '/':
244 handleForwardSlash ( event );
245 return;
246 default:
247 break;
248 }
249 event.Skip();
250 }
251
handleBackspace(wxKeyEvent & event)252 void XmlCtrl::handleBackspace ( wxKeyEvent& event )
253 {
254 protectHeadLine();
255
256 validationRequired = true;
257
258 if ( canMoveLeftAt ( GetCurrentPos() ) )
259 {
260 DeleteBack();//event.Skip();
261 return;
262 }
263
264 int currentPos, limitPos;
265 currentPos = GetCurrentPos();
266 if ( currentPos < 1 )
267 return;
268
269 limitPos = currentPos - 1;
270
271 // tag
272 int limitStyle = getLexerStyleAt ( limitPos );
273 if ( GetCharAt ( limitPos ) == '>' &&
274 ( limitStyle == wxSTC_H_TAG ||
275 limitStyle == wxSTC_H_TAGUNKNOWN ||
276 limitStyle == wxSTC_H_TAGEND ||
277 limitStyle == wxSTC_H_XMLSTART ||
278 limitStyle == wxSTC_H_XMLEND ) )
279 {
280 if ( GetSelectionStart() != GetSelectionEnd() )
281 {
282 if ( *protectTags )
283 adjustSelection();
284 else
285 DeleteBack();//event.Skip();
286 return;
287 }
288 if ( !properties.deleteWholeTag )
289 {
290 if ( ! ( *protectTags ) )
291 DeleteBack();//event.Skip();
292 return;
293 }
294 // delete tag to left of caret
295 for ( ;
296 limitPos &&
297 GetCharAt ( limitPos ) != '<';
298 limitPos-- )
299 ;
300 SetSelection ( currentPos, limitPos );
301 if ( *protectTags )
302 {
303 SetReadOnly ( true ); // needed to prevent erroneous BS insertion by control
304 int ret =
305 wxMessageBox ( _ ( "Delete tag?" ),
306 _ ( "Tags Locked" ),
307 wxOK | wxCANCEL | wxICON_QUESTION );
308 SetReadOnly ( false );
309 if ( ret != wxOK )
310 {
311 return;
312 }
313 // ensure selection is set correctly
314 if ( GetSelectionStart() != currentPos || GetSelectionEnd() != limitPos )
315 SetSelection ( currentPos, limitPos );
316 }
317 DeleteBack();
318 return;
319 }
320
321 // entity reference
322 else if ( GetCharAt ( limitPos ) == ';' && getLexerStyleAt ( limitPos ) == wxSTC_H_ENTITY )
323 {
324 // delete entity to left of caret
325 for ( ;
326 limitPos &&
327 getLexerStyleAt ( limitPos ) == wxSTC_H_ENTITY &&
328 GetCharAt ( limitPos ) != '&';
329 limitPos-- )
330 ;
331 SetSelection ( limitPos, currentPos );
332 if ( *protectTags )
333 {
334 SetReadOnly ( true ); // needed to prevent erroneous BS insertion by control
335 int ret =
336 wxMessageBox ( _ ( "Delete entity reference?" ),
337 _ ( "Tags Locked" ),
338 wxOK | wxCANCEL | wxICON_QUESTION );
339 SetReadOnly ( false );
340 if ( ret != wxOK )
341 return;
342 // ensure selection is set correctly
343 if ( GetSelectionStart() != currentPos || GetSelectionEnd() != limitPos )
344 SetSelection ( currentPos, limitPos );
345 }
346 DeleteBack();
347 return;
348 }
349 else if ( *protectTags )
350 {
351 return;
352 }
353 event.Skip();
354 }
355
handleDelete(wxKeyEvent & event)356 void XmlCtrl::handleDelete ( wxKeyEvent& event )
357 {
358 protectHeadLine();
359
360 validationRequired = true;
361
362 if ( !canMoveRightAt ( GetCurrentPos() ) &&
363 GetSelectionStart() == GetSelectionEnd() )
364 {
365 int currentPos, limitPos;
366 limitPos = currentPos = GetCurrentPos();
367
368 // tag
369 int limitStyle = getLexerStyleAt ( limitPos );
370 if ( GetCharAt ( limitPos ) == '<' &&
371 ( limitStyle == wxSTC_H_TAG ||
372 limitStyle == wxSTC_H_TAGUNKNOWN ||
373 limitStyle == wxSTC_H_TAGEND ||
374 limitStyle == wxSTC_H_XMLSTART ||
375 limitStyle == wxSTC_H_XMLEND
376 ) )
377 {
378 if ( GetSelectionStart() != GetSelectionEnd() )
379 {
380 if ( *protectTags )
381 adjustSelection();
382 else
383 DeleteBack();//event.Skip();
384 return;
385 }
386 if ( !properties.deleteWholeTag )
387 {
388 if ( ! ( *protectTags ) )
389 DeleteBack();//event.Skip();
390 return;
391 }
392
393 for ( ;
394 GetCharAt ( limitPos ) != '>' && limitPos < GetLength();
395 limitPos++ )
396 {
397 if ( limitPos > ( currentPos + BUFSIZ ) )
398 {
399 DeleteBack();//event.Skip();
400 return;
401 }
402 }
403 if ( currentPos != limitPos )
404 {
405 SetSelection ( currentPos, limitPos + 1 );
406 if ( *protectTags )
407 {
408 int ret =
409 wxMessageBox ( _ ( "Delete tag?" ),
410 _ ( "Tags Locked" ),
411 wxOK | wxCANCEL | wxICON_QUESTION );
412 if ( ret != wxOK )
413 return;
414 }
415 DeleteBack();
416 return;
417 }
418 }
419 // entity
420 else if ( GetCharAt ( limitPos ) == '&' && getLexerStyleAt ( limitPos ) == wxSTC_H_ENTITY )
421 {
422 for ( ;
423 getLexerStyleAt ( limitPos ) == wxSTC_H_ENTITY && limitPos <= GetLength();
424 limitPos++ )
425 {
426 if ( GetCharAt ( limitPos ) == ';' )
427 break;
428 else if ( GetCharAt ( limitPos ) == '\n' || limitPos > ( currentPos + BUFSIZ ) )
429 {
430 DeleteBack();//event.Skip();
431 return;
432 }
433 }
434 if ( currentPos != limitPos )
435 {
436 SetSelection ( currentPos, limitPos + 1 );
437 if ( *protectTags )
438 {
439 int ret =
440 wxMessageBox ( _ ( "Delete entity reference?" ),
441 _ ( "Tags Locked" ),
442 wxOK | wxCANCEL | wxICON_QUESTION );
443 if ( ret != wxOK )
444 return;
445 }
446 DeleteBack();
447 return;
448 }
449 }
450
451 else if ( *protectTags )
452 return;
453 }
454 event.Skip();
455 }
456
handleOpenAngleBracket(wxKeyEvent & event)457 void XmlCtrl::handleOpenAngleBracket ( wxKeyEvent& event )
458 {
459 if ( AutoCompActive() )
460 AutoCompCancel();
461
462 validationRequired = true;
463
464 if ( *protectTags )
465 {
466 AddText ( _T ( "<" ) );
467 return;
468 }
469
470 AddText ( _T ( "<" ) );
471
472 int pos = GetCurrentPos();
473
474 // exit conditions based on style
475 int style = getLexerStyleAt ( pos );
476 switch ( style )
477 {
478 case wxSTC_H_DOUBLESTRING:
479 case wxSTC_H_SINGLESTRING:
480 return;
481 default:
482 break;
483 }
484
485 // determine parent element
486 int parentCloseAngleBracket;
487 parentCloseAngleBracket = getParentCloseAngleBracket ( pos );
488
489 if ( parentCloseAngleBracket < 0 )
490 return;
491
492 wxString parent = getLastElementName ( parentCloseAngleBracket );
493 if ( elementMap.find ( parent ) == elementMap.end() )
494 return;
495
496 wxString choice;
497 std::set<wxString> &childSet = elementMap[parent];
498 std::set<wxString>::iterator it;
499 for ( it = childSet.begin(); it != childSet.end(); ++it )
500 {
501 if ( !choice.empty() )
502 choice.append ( _T ( "<" ) );
503 choice.append ( *it );
504 }
505 if ( !choice.empty() )
506 UserListShow ( 0, choice );
507 }
508
handleCloseAngleBracket(wxKeyEvent & event)509 void XmlCtrl::handleCloseAngleBracket ( wxKeyEvent& event )
510 {
511 if ( AutoCompActive() )
512 AutoCompCancel();
513
514 validationRequired = true;
515
516 if ( *protectTags )
517 {
518 AddText ( _T ( ">" ) );
519 return;
520 }
521
522 wxString insertBuffer;
523 int pos;
524 pos = GetCurrentPos();
525
526 wxString elementName = getLastElementName ( pos );
527 if ( !elementName.empty() )
528 {
529 attributeMap[elementName]; // Just want to put it there
530 }
531
532 // exit condition 1
533 if ( pos <= 1 )
534 {
535 event.Skip();
536 return;
537 }
538 // exit condition 2 (empty tag/end of CDATA section)
539 else if ( GetCharAt ( pos - 1 ) == '/' ||
540 GetCharAt ( pos - 1 ) == ']' )
541 {
542 event.Skip();
543 return;
544 }
545 // exit condition 3 (comment/CDATA)
546 else if ( getLexerStyleAt ( pos - 1 ) == wxSTC_H_COMMENT ||
547 getLexerStyleAt ( pos - 1 ) == wxSTC_H_CDATA ||
548 ( getLexerStyleAt ( pos - 1 ) == wxSTC_H_DOUBLESTRING && ( GetCharAt ( pos - 1 ) != '"' ) ) ||
549 ( getLexerStyleAt ( pos - 1 ) == wxSTC_H_SINGLESTRING && ( GetCharAt ( pos - 1 ) != '\'' ) ) )
550 {
551 event.Skip();
552 return;
553 }
554
555 if ( !elementName.empty() )
556 {
557 if ( !properties.insertCloseTag )
558 {
559 event.Skip();
560 return;
561 }
562 AddText ( _T ( ">" ) );
563 insertBuffer += _T ( "</" );
564 insertBuffer += elementName;
565 insertBuffer += _T ( ">" );
566 InsertText ( pos + 1, insertBuffer );
567 SetSelection ( pos + 1, pos + 1 );
568 }
569 else
570 event.Skip();
571 }
572
handleEquals(wxKeyEvent & event)573 void XmlCtrl::handleEquals ( wxKeyEvent& event )
574 {
575 if ( AutoCompActive() )
576 AutoCompCancel();
577
578 int pos = GetCurrentPos();
579 if ( pos <= 0 || getLexerStyleAt ( pos - 1 ) != wxSTC_H_ATTRIBUTE )
580 {
581 event.Skip();
582 return;
583 }
584 AddText ( _T ( "=\"\"" ) );
585 SetSelection ( pos + 2, pos + 2 );
586
587 // tbd: identify possible attribute values
588 wxString choice, elementName, attributeName;
589 elementName = getLastElementName ( pos );
590 attributeName = getLastAttributeName ( pos );
591
592 std::set<wxString> &valueSet = attributeMap[elementName][attributeName];
593 if ( valueSet.empty() )
594 return;
595
596 std::set<wxString>::iterator valueSetIterator;
597 int cutoff = BUFSIZ;
598 for ( valueSetIterator = valueSet.begin();
599 valueSetIterator != valueSet.end();
600 ++valueSetIterator )
601 {
602 if ( ! ( cutoff-- ) )
603 break;
604 if ( !choice.empty() )
605 choice.Append ( _T ( "<" ) );
606 choice.Append ( *valueSetIterator );
607 }
608
609 if ( !choice.empty() )
610 UserListShow ( 0, choice );
611 }
612
handleSpace(wxKeyEvent & event)613 void XmlCtrl::handleSpace ( wxKeyEvent& event )
614 {
615 if ( AutoCompActive() )
616 AutoCompCancel();
617
618 int pos = GetCurrentPos();
619 if ( pos <= 2 )
620 {
621 event.Skip();
622 return;
623 }
624
625 int prevPos;
626 char c = getPrevNonSpaceChar ( pos, &prevPos );
627 int style = getLexerStyleAt ( prevPos );
628
629 bool proceed = false;
630 // space pressed after element name
631 if (
632 style == wxSTC_H_TAG ||
633 style == wxSTC_H_TAGUNKNOWN ||
634 style == wxSTC_H_ATTRIBUTEUNKNOWN ||
635 style == wxSTC_H_ATTRIBUTE )
636 {
637 proceed = true;
638 }
639 // space pressed after attribute value
640 else if (
641 ( style == wxSTC_H_DOUBLESTRING ||
642 style == wxSTC_H_SINGLESTRING ) &&
643 ( c == '\'' || c == '"' ) &&
644 getPrevNonSpaceChar ( prevPos - 1, NULL ) != '=' )
645 {
646 proceed = true;
647 }
648
649 int tagStartPos = getTagStartPos ( pos );
650 if ( !proceed || tagStartPos == -1 )
651 {
652 event.Skip();
653 return;
654 }
655
656 AddText ( _T ( " " ) );
657
658 wxString elementName = getLastElementName ( pos );
659 if ( attributeMap.find ( elementName ) == attributeMap.end() )
660 return;
661
662 wxString choice;
663 wxString tag = GetTextRange ( tagStartPos, pos );
664 std::map<wxString, std::set<wxString> > &curAttMap = attributeMap[elementName];
665 std::map<wxString, std::set<wxString> >::iterator it;
666 for ( it = curAttMap.begin(); it != curAttMap.end(); ++it )
667 {
668 // avoid duplicate attributes
669 if ( tag.Contains ( it->first + _T ( "=" ) ) )
670 continue;
671
672 if ( !choice.empty() )
673 choice.Append ( _T ( "<" ) );
674 choice.Append ( it->first );
675 }
676 if ( !choice.empty() )
677 {
678 UserListShow ( 0, choice );
679 validationRequired = true;
680 }
681 }
682
handleAmpersand(wxKeyEvent & event)683 void XmlCtrl::handleAmpersand ( wxKeyEvent& event )
684 {
685 if ( AutoCompActive() )
686 AutoCompCancel();
687
688 validationRequired = true;
689
690 if ( *protectTags )
691 {
692 AddText ( _T ( "&" ) );
693 return;
694 }
695
696 int pos, style;
697 pos = GetCurrentPos();
698 style = getLexerStyleAt ( pos );
699 if ( style != wxSTC_H_COMMENT &&
700 style != wxSTC_H_CDATA &&
701 style != wxSTC_H_TAGUNKNOWN &&
702 entitySet.size() >= 4 ) // min. 4 default entities
703 {
704 AddText ( _T ( "&" ) );
705 wxString choice;
706 std::set<wxString>::iterator it = entitySet.begin();
707 choice += *it;
708 choice += _T ( ";" );
709 for ( it++; it != entitySet.end(); ++it )
710 {
711 choice += _T ( "<" );
712 choice += *it;
713 choice += _T ( ";" );
714 }
715 UserListShow ( 0, choice );
716 }
717 else
718 event.Skip();
719 }
720
handleForwardSlash(wxKeyEvent & event)721 void XmlCtrl::handleForwardSlash ( wxKeyEvent& event )
722 {
723 if ( AutoCompActive() )
724 AutoCompCancel();
725
726 int pos = GetCurrentPos();
727 if (
728 ( pos <= 0 ) ||
729 GetCharAt ( pos - 1 ) != '<' ||
730 getLexerStyleAt ( pos ) == wxSTC_H_COMMENT ||
731 getLexerStyleAt ( pos ) == wxSTC_H_CDATA )
732 {
733 event.Skip();
734 return;
735 }
736
737 AddText ( _T ( "/" ) );
738
739 int parentCloseAngleBracket = getParentCloseAngleBracket ( pos );
740 if ( parentCloseAngleBracket < 0 )
741 return;
742
743 wxString wideParent = getLastElementName ( parentCloseAngleBracket );
744 if ( wideParent.empty() )
745 return;
746 AddText ( wideParent + _T ( ">" ) );
747 validationRequired = true;
748 }
749
OnKeyPressed(wxKeyEvent & event)750 void XmlCtrl::OnKeyPressed ( wxKeyEvent& event )
751 {
752 if ( *protectTags && GetSelectionStart() != GetSelectionEnd() )
753 {
754 adjustSelection();
755 }
756 if ( *protectTags )
757 SetOvertype ( false );
758
759 int pos, iteratorPos, maxPos;
760 char c;
761 wxString s;
762 switch ( event.GetKeyCode() )
763 {
764 case WXK_RETURN:
765 if ( AutoCompActive() )
766 {
767 AutoCompComplete();
768 return;
769 }
770
771 if ( *protectTags )
772 adjustPosRight();
773
774 insertNewLine();
775 return;
776 case WXK_RIGHT:
777 pos = GetCurrentPos();
778
779 if ( *protectTags && !canMoveRightAt ( pos ) )
780 {
781 SetSelection ( pos + 1, pos + 1 );
782 adjustPosRight();
783 return;
784 }
785
786 maxPos = GetLength();
787 c = GetCharAt ( pos );
788 if ( c == '<' && event.ControlDown() && !event.ShiftDown() )
789 {
790 for (
791 iteratorPos = pos;
792 iteratorPos < maxPos &&
793 GetCharAt ( iteratorPos ) != ' ' &&
794 GetCharAt ( iteratorPos ) != '>' &&
795 GetCharAt ( iteratorPos ) != '\n';
796 ++iteratorPos )
797 ;
798 ++iteratorPos;
799 SetSelection ( iteratorPos, iteratorPos );
800 return;
801 }
802 else
803 break;
804 case WXK_LEFT:
805 pos = GetCurrentPos();
806 if ( *protectTags && !canMoveLeftAt ( pos ) )
807 {
808 adjustPosLeft();
809 return;
810 }
811
812 if ( pos < 3 )
813 break;
814 c = GetCharAt ( pos - 1 );
815 if ( c == '>' && event.ControlDown() && !event.ShiftDown() )
816 {
817 for (
818 iteratorPos = pos - 1;
819 iteratorPos > 0 &&
820 GetCharAt ( iteratorPos ) != '<' &&
821 GetCharAt ( iteratorPos ) != ' ' &&
822 GetCharAt ( iteratorPos ) != '=' &&
823 GetCharAt ( iteratorPos ) != '\n';
824 --iteratorPos )
825 ;
826 if (
827 GetCharAt ( iteratorPos ) != '<' &&
828 GetCharAt ( iteratorPos ) != '=' )
829 ++iteratorPos;
830 SetSelection ( iteratorPos, iteratorPos );
831 return;
832 }
833 else
834 break;
835 case WXK_UP:
836 if ( *protectTags )
837 {
838 LineUp();
839 if ( !canInsertAt ( GetCurrentPos() ) )
840 adjustPosLeft();
841 return;
842 }
843 break;
844 case WXK_DOWN:
845 if ( *protectTags )
846 {
847 LineDown();
848 if ( !canInsertAt ( GetCurrentPos() ) )
849 adjustPosRight();
850 return;
851 }
852 break;
853 case WXK_INSERT:
854 if ( *protectTags )
855 return;
856 break;
857 case WXK_BACK:
858 handleBackspace ( event );
859 validationRequired = true;
860 return;
861 case WXK_TAB:
862 if ( *protectTags )
863 {
864 if ( !canInsertAt ( GetCurrentPos() ) )
865 adjustPosRight();
866 }
867 break;
868 case WXK_HOME:
869 if ( *protectTags && !event.ControlDown() && !event.ShiftDown() )
870 {
871 Home();
872 if ( !canInsertAt ( GetCurrentPos() ) )
873 adjustPosLeft();
874 return;
875 }
876 break;
877 case WXK_END:
878 if ( *protectTags && !event.ControlDown() && !event.ShiftDown() )
879 {
880 LineEnd();
881 if ( !canInsertAt ( GetCurrentPos() ) )
882 adjustPosRight();
883 return;
884 }
885 break;
886 case WXK_PAGEUP:
887 if ( *protectTags )
888 {
889 PageUp();
890 if ( !canInsertAt ( GetCurrentPos() ) )
891 adjustPosLeft();
892 return;
893 }
894 break;
895 case WXK_PAGEDOWN:
896 if ( *protectTags )
897 {
898 PageDown();
899 if ( !canInsertAt ( GetCurrentPos() ) )
900 adjustPosRight();
901 return;
902 }
903 break;
904 case WXK_DELETE:
905 handleDelete ( event );
906 validationRequired = true;
907 return;
908 default:
909 break;
910 }
911 event.Skip();
912 }
913
getLastElementName(int pos)914 wxString XmlCtrl::getLastElementName ( int pos )
915 {
916 if ( pos < 1 )
917 return _T ( "" );
918
919 int startPos, iteratorPos;
920
921 for ( startPos = pos - 1; startPos >= 0; --startPos )
922 {
923 char c = GetCharAt ( startPos );
924 if ( c == '>' )
925 return _T ( "" );
926 else if ( c == '<' )
927 break;
928 }
929
930 // exit if not found or closing/declaration/command tag
931 if ( GetCharAt ( startPos ) != '<' ||
932 GetCharAt ( startPos + 1 ) == '/' ||
933 GetCharAt ( startPos + 1 ) == '?' ||
934 GetCharAt ( startPos + 1 ) == '!' )
935 return _T ( "" );
936
937 ++startPos;
938 for ( iteratorPos = startPos;
939 iteratorPos < pos &&
940 GetCharAt ( iteratorPos ) != ' ' &&
941 GetCharAt ( iteratorPos ) != '\n' &&
942 GetCharAt ( iteratorPos ) != '\t' &&
943 GetCharAt ( iteratorPos ) != '/' &&
944 GetCharAt ( iteratorPos ) != '>';
945 ++iteratorPos )
946 ;
947 if ( startPos == iteratorPos )
948 return _T ( "" );
949 return GetTextRange ( startPos, iteratorPos );
950 }
951
getChildren(const wxString & parent)952 const std::set<wxString> &XmlCtrl::getChildren ( const wxString& parent )
953 {
954 static std::set<wxString> mySet;
955 if ( elementMap.find ( parent ) == elementMap.end() )
956 return mySet;
957
958 return elementMap[parent];
959 }
960
getLastAttributeName(int pos)961 wxString XmlCtrl::getLastAttributeName ( int pos )
962 {
963 if ( pos < 1 )
964 return _T ( "" );
965
966 int startPos;
967
968 for ( startPos = pos - 1; startPos >= 0; --startPos )
969 {
970 char c = GetCharAt ( startPos );
971 if ( c == ' ' || c == '<' )
972 break;
973 }
974
975 if ( GetCharAt ( startPos ) != ' ' ||
976 startPos >= pos - 1 )
977 return _T ( "" );
978
979 return GetTextRange ( startPos + 1, pos );
980 }
981
findNextEndTag(int pos,unsigned depth,int character,int range)982 int XmlCtrl::findNextEndTag (
983 int pos,
984 unsigned depth /*= 1*/,
985 int character /*= '>'*/,
986 int range /*= USHRT_MAX * 4*/ )
987 {
988 wxASSERT ( character == '<' || character == '>' );
989
990 unsigned openAngleBrackets = 0;
991 int cutoff = pos + range;
992 if ( cutoff > GetEndStyled() )
993 cutoff = GetEndStyled();
994 for ( ; pos < cutoff; ++pos )
995 {
996 int ch = GetCharAt ( pos );
997 if ( ch == '<' )
998 openAngleBrackets = ( openAngleBrackets << 1 ) | 1;// Just a flag
999 // Check for empty tags, which have start tags but no end tags
1000 if ( character != '>' || !openAngleBrackets )
1001 if ( ch == '>' && getLexerStyleAt ( pos ) == wxSTC_H_TAGEND )
1002 --depth;
1003 if ( ch != character )
1004 continue;
1005
1006 int style = getLexerStyleAt ( pos );
1007 if ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN )
1008 {
1009 int type = getTagType ( pos );
1010 switch ( type )
1011 {
1012 case TAG_TYPE_CLOSE:
1013 --depth;
1014 break;
1015 case TAG_TYPE_OPEN:
1016 // In case that the cursor is inside a start tag
1017 if ( character != '>' || openAngleBrackets > 0 )
1018 ++depth;
1019 break;
1020 case TAG_TYPE_EMPTY:
1021 case TAG_TYPE_OTHER:
1022 case TAG_TYPE_ERROR:
1023 break;
1024 }
1025 }
1026
1027 if ( !depth )
1028 return pos + 1;
1029 }
1030 return -1;
1031 }
1032
findPreviousStartTag(int pos,unsigned depth,int character,int range)1033 int XmlCtrl::findPreviousStartTag (
1034 int pos,
1035 unsigned depth /*= 1*/,
1036 int character /*= '<'*/,
1037 int range /*= USHRT_MAX * 4*/ )
1038 {
1039 wxASSERT ( character == '<' || character == '>' );
1040
1041 int cutoff = ( ( pos - range ) > 2 ) ? pos - range : 2;
1042 unsigned closeAngleBrackets = 0;
1043 while ( pos-- > cutoff )
1044 {
1045 int ch = GetCharAt ( pos );
1046 if ( ch == '>' )
1047 {
1048 closeAngleBrackets = ( closeAngleBrackets << 1 ) | 1;// Just a flag
1049 // Check for empty tags, which have start tags but no end tags
1050 if ( character != '>' && getLexerStyleAt ( pos ) == wxSTC_H_TAGEND )
1051 ++depth;
1052 }
1053 if ( ch != character )
1054 continue;
1055
1056 int style = getLexerStyleAt ( pos );
1057 if ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN )
1058 {
1059 int type = getTagType ( pos );
1060 switch ( type )
1061 {
1062 case TAG_TYPE_CLOSE:
1063 // If the cursor is already in an end tag
1064 if ( character != '<' || closeAngleBrackets > 0 )
1065 ++depth;
1066 break;
1067 case TAG_TYPE_OPEN:
1068 --depth;
1069 break;
1070 case TAG_TYPE_EMPTY:
1071 case TAG_TYPE_OTHER:
1072 case TAG_TYPE_ERROR:
1073 break;
1074 }
1075 }
1076 if ( !depth )
1077 return pos;
1078 }
1079 return -1;
1080 }
1081
adjustNoColumnWidth()1082 void XmlCtrl::adjustNoColumnWidth()
1083 {
1084 int maxLine = GetLineCount();
1085 if ( maxLine == currentMaxLine )
1086 return;
1087
1088 int digits, charWidth, width;
1089 digits = 0;
1090 do
1091 {
1092 ++digits;
1093 maxLine /= 10;
1094 }
1095 while ( maxLine );
1096 digits = ( digits > 2 ) ? digits : 2;
1097 charWidth = TextWidth ( wxSTC_STYLE_LINENUMBER, _T ( "9" ) );
1098 width = ( digits + 2 ) * charWidth;
1099 SetMarginWidth ( 0, width );
1100 currentMaxLine = maxLine;
1101 }
1102
updatePromptMaps()1103 void XmlCtrl::updatePromptMaps()
1104 {
1105 std::string bufferUtf8 = myGetTextRaw();
1106
1107 updatePromptMaps ( bufferUtf8.c_str(), bufferUtf8.size() );
1108 }
1109
updatePromptMaps(const char * utf8Buffer,size_t bufferLen)1110 void XmlCtrl::updatePromptMaps ( const char *utf8Buffer, size_t bufferLen )
1111 {
1112 attributeMap.clear();
1113 elementMap.clear();
1114 elementStructureMap.clear();
1115
1116 wxCriticalSectionLocker locker ( xmlcopyeditorCriticalSection );
1117
1118 if ( mPromptGeneratorThread )
1119 return;
1120
1121 mPromptGeneratorThread = new XmlPromptGenerator (
1122 GetEventHandler(), utf8Buffer, bufferLen, basePath, auxPath, "UTF-8"
1123 );
1124
1125 if ( mPromptGeneratorThread->Create() != wxTHREAD_NO_ERROR
1126 || mPromptGeneratorThread->Run() != wxTHREAD_NO_ERROR )
1127 {
1128 delete mPromptGeneratorThread;
1129 mPromptGeneratorThread = NULL;
1130 }
1131 }
1132
OnPromptGenerated(wxNotifyEvent & event)1133 void XmlCtrl::OnPromptGenerated ( wxNotifyEvent &event )
1134 {
1135 wxCriticalSectionLocker locker ( xmlcopyeditorCriticalSection );
1136
1137 if ( mPromptGeneratorThread == NULL )
1138 return;
1139
1140 attributeMap = mPromptGeneratorThread->getAttributeMap();
1141 requiredAttributeMap = mPromptGeneratorThread->getRequiredAttributeMap();
1142 elementMap = mPromptGeneratorThread->getElementMap();
1143 elementStructureMap = mPromptGeneratorThread->getElementStructureMap();
1144 entitySet = mPromptGeneratorThread->getEntitySet();
1145 grammarFound = mPromptGeneratorThread->getGrammarFound();
1146 entitySet.insert ( _T ( "amp" ) );
1147 entitySet.insert ( _T ( "apos" ) );
1148 entitySet.insert ( _T ( "quot" ) );
1149 entitySet.insert ( _T ( "lt" ) );
1150 entitySet.insert ( _T ( "gt" ) );
1151
1152 mPromptGeneratorThread->Wait();
1153 delete mPromptGeneratorThread;
1154 mPromptGeneratorThread = NULL;
1155
1156 wxPostEvent ( GetParent()->GetEventHandler(), event );
1157 }
1158
applyProperties(const XmlCtrlProperties & propertiesParameter,bool zoomOnly)1159 void XmlCtrl::applyProperties (
1160 const XmlCtrlProperties &propertiesParameter,
1161 bool zoomOnly )
1162 {
1163 properties = propertiesParameter;
1164
1165 SetZoom ( ( type != FILE_TYPE_BINARY ) ? properties.zoom : 0 );
1166
1167 if ( zoomOnly )
1168 return;
1169
1170 SetCaretLineVisible ( properties.currentLine );
1171 SetIndentationGuides (
1172 ( type != FILE_TYPE_BINARY ) ? properties.indentLines : false );
1173 SetWrapMode ( ( type != FILE_TYPE_BINARY ) ? properties.wrap : false );
1174 SetViewWhiteSpace (
1175 ( properties.whitespaceVisible ) ?
1176 wxSTC_WS_VISIBLEAFTERINDENT : wxSTC_WS_INVISIBLE );
1177
1178 switch ( type )
1179 {
1180 case FILE_TYPE_BINARY:
1181 SetLexer ( wxSTC_LEX_NULL );
1182 break;
1183 case FILE_TYPE_CSS:
1184 SetLexer ( wxSTC_LEX_CSS );
1185 break;
1186 default:
1187 SetLexer ( wxSTC_LEX_XML );
1188 break;
1189 }
1190
1191 setColorScheme (
1192 ( type != FILE_TYPE_BINARY ) ? properties.colorScheme : COLOR_SCHEME_NONE );
1193
1194 // line no margin
1195 if ( properties.number ) // permit line nos for large files
1196 {
1197 SetMarginType ( 0, wxSTC_MARGIN_NUMBER ); // width set at idle time
1198 adjustNoColumnWidth();
1199 }
1200 else
1201 SetMarginWidth ( 0, 0 );
1202
1203 SetMarginWidth ( 1, 0 );
1204
1205 if ( properties.fold && type != FILE_TYPE_BINARY )
1206 {
1207 // folding margin
1208 SetMarginType ( 2, wxSTC_MARGIN_SYMBOL );
1209 SetMarginMask ( 2, wxSTC_MASK_FOLDERS );
1210 SetMarginSensitive ( 2, true );
1211 SetMarginWidth ( 2, 16 );
1212
1213 // define folding markers
1214 wxColor clrWnd = wxSystemSettings::GetColour ( wxSYS_COLOUR_WINDOW );
1215 wxColor clrText = wxSystemSettings::GetColour ( wxSYS_COLOUR_WINDOWTEXT );
1216 MarkerDefine ( wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, clrWnd, clrText );
1217 MarkerDefine ( wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, clrWnd, clrText );
1218 MarkerDefine ( wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, clrWnd, clrText );
1219 MarkerDefine ( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, clrWnd, clrText );
1220 MarkerDefine ( wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, clrWnd, clrText );
1221 MarkerDefine ( wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, clrWnd, clrText );
1222 MarkerDefine ( wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, clrWnd, clrText );
1223 }
1224 else
1225 {
1226 SetMarginWidth ( 2, 0 );
1227 }
1228
1229 if ( type != FILE_TYPE_BINARY )
1230 {
1231 Colourise ( 0, -1 );
1232 }
1233
1234 wxString value = ( properties.fold && type != FILE_TYPE_BINARY ) ? _T ( "1" ) : _T ( "0" );
1235 SetProperty ( _T ( "fold" ), value );
1236 SetProperty ( _T ( "fold.html" ), value );
1237 value = properties.foldCompact ? value : _T("0");
1238 SetProperty ( _T ( "fold.compact" ), value );
1239 }
1240
OnMarginClick(wxStyledTextEvent & event)1241 void XmlCtrl::OnMarginClick ( wxStyledTextEvent& event )
1242 {
1243 const int line = LineFromPosition ( event.GetPosition() );
1244 const int margin = event.GetMargin();
1245
1246 // let others process this first
1247 if ( GetParent()->GetEventHandler()->ProcessEvent ( event ) )
1248 return;
1249
1250 if ( margin == 2 )
1251 {
1252 const int level = GetFoldLevel ( line );
1253 if ( ( ( level ) & ( wxSTC_FOLDLEVELHEADERFLAG ) ) != 0 )
1254 ToggleFold ( line );
1255 }
1256 else
1257 event.Skip();
1258 }
1259
OnMouseLeftDown(wxMouseEvent & event)1260 void XmlCtrl::OnMouseLeftDown ( wxMouseEvent& event )
1261 {
1262 SetMouseDownCaptures ( !*protectTags );
1263 event.Skip();
1264 }
1265
OnMouseLeftUp(wxMouseEvent & event)1266 void XmlCtrl::OnMouseLeftUp ( wxMouseEvent& event )
1267 {
1268 event.Skip();
1269 if ( *protectTags && !canInsertAt ( GetCurrentPos() ) )
1270 adjustPosRight();
1271 }
1272
OnMouseRightUp(wxMouseEvent & event)1273 void XmlCtrl::OnMouseRightUp ( wxMouseEvent& event )
1274 {
1275 if ( *protectTags )
1276 return;
1277 event.Skip();
1278 }
1279
isCloseTag(int pos)1280 bool XmlCtrl::isCloseTag ( int pos )
1281 {
1282 int iteratorPos;
1283 for ( iteratorPos = pos; iteratorPos >= 0; --iteratorPos )
1284 {
1285 if ( GetCharAt ( iteratorPos ) == '<' && getLexerStyleAt ( iteratorPos ) == wxSTC_H_TAG )
1286 return ( GetCharAt ( iteratorPos + 1 ) == '/' ) ? true : false;
1287 }
1288 return false;
1289 }
1290
getTagStartPos(int pos)1291 int XmlCtrl::getTagStartPos ( int pos )
1292 {
1293 int iteratorPos;
1294 for ( iteratorPos = pos; iteratorPos >= 0; --iteratorPos )
1295 {
1296 if ( GetCharAt ( iteratorPos ) == '<' && getLexerStyleAt ( iteratorPos ) == wxSTC_H_TAG )
1297 return iteratorPos;
1298 }
1299 return -1;
1300 }
1301
getAttributeStartPos(int pos)1302 int XmlCtrl::getAttributeStartPos ( int pos )
1303 {
1304 int iteratorPos;
1305 char c;
1306 bool attributeSeen = false;
1307 for ( iteratorPos = pos; iteratorPos > 0; iteratorPos-- )
1308 {
1309 c = GetCharAt ( iteratorPos );
1310 if ( ( getLexerStyleAt ( iteratorPos ) ) == wxSTC_H_ATTRIBUTE )
1311 attributeSeen = true;
1312 else if ( ( c == ' ' || c == '\t' || c == '\n' ) && attributeSeen )
1313 return iteratorPos;
1314 }
1315 return -1;
1316 }
1317
getAttributeSectionEndPos(int pos,int range)1318 int XmlCtrl::getAttributeSectionEndPos ( int pos, int range )
1319 {
1320 int iteratorPos, limit, style;
1321 limit = pos + range;
1322
1323 for ( iteratorPos = pos; iteratorPos < limit; iteratorPos++ )
1324 {
1325 style = getLexerStyleAt ( iteratorPos );
1326 switch ( style )
1327 {
1328 case wxSTC_H_TAG:
1329 case wxSTC_H_TAGEND:
1330 case wxSTC_H_XMLEND:
1331 case wxSTC_H_QUESTION:
1332 return iteratorPos;
1333 default:
1334 continue;
1335 }
1336 }
1337 return -1;
1338 }
1339
adjustCursor()1340 void XmlCtrl::adjustCursor()
1341 {
1342 if ( !canInsertAt ( GetCurrentPos() ) )
1343 adjustPosRight();
1344 }
1345
canInsertAt(int pos)1346 bool XmlCtrl::canInsertAt ( int pos )
1347 {
1348 if ( pos < 0 )
1349 return false;
1350
1351 int style = getLexerStyleAt ( pos );
1352 switch ( style )
1353 {
1354 case wxSTC_H_TAG:
1355 case wxSTC_H_TAGUNKNOWN:
1356 case wxSTC_H_QUESTION:
1357 case wxSTC_H_CDATA:
1358 case wxSTC_H_COMMENT:
1359 case wxSTC_H_SGML_DEFAULT:
1360 return ( GetCharAt ( pos ) == '<' ) ? true : false;
1361 case wxSTC_H_ENTITY:
1362 return ( GetCharAt ( pos ) == '&' ) ? true : false;
1363 case wxSTC_H_DEFAULT:
1364 return true;
1365 }
1366 return false;
1367 }
1368
canMoveRightAt(int pos)1369 bool XmlCtrl::canMoveRightAt ( int pos )
1370 {
1371 int style = getLexerStyleAt ( pos );
1372 switch ( style )
1373 {
1374 case wxSTC_H_DEFAULT:
1375 return true;
1376 }
1377 return false;
1378 }
1379
canMoveLeftAt(int pos)1380 bool XmlCtrl::canMoveLeftAt ( int pos )
1381 {
1382 if ( pos < 1 )
1383 return false;
1384
1385 int style = getLexerStyleAt ( pos - 1 );
1386 switch ( style )
1387 {
1388 case wxSTC_H_DEFAULT:
1389 return true;
1390 }
1391 return false;
1392 }
1393
adjustPosRight()1394 void XmlCtrl::adjustPosRight()
1395 {
1396 int pos, max;
1397 pos = GetCurrentPos();
1398 max = GetLength();
1399 for ( ; pos <= max; pos++ )
1400 if ( canInsertAt ( pos ) )
1401 {
1402 break;
1403 }
1404 SetSelection ( pos, pos );
1405 }
1406
adjustPosLeft()1407 void XmlCtrl::adjustPosLeft()
1408 {
1409 int pos;
1410 pos = GetCurrentPos() - 1;
1411 if ( pos < 0 )
1412 {
1413 SetSelection ( 0, 0 );
1414 return;
1415 }
1416 for ( ; pos > 0; pos-- )
1417 if ( canInsertAt ( pos ) )
1418 {
1419 break;
1420 }
1421 SetSelection ( pos, pos );
1422 }
1423
adjustSelection()1424 void XmlCtrl::adjustSelection()
1425 {
1426 int start, end, iterator;
1427 start = GetSelectionStart();
1428 end = GetSelectionEnd();
1429
1430 // exit condition 1
1431 if ( start == end && canInsertAt ( start ) )
1432 return;
1433
1434 // exit condition 2
1435 else if ( !canInsertAt ( start ) || start > end )
1436 {
1437 SetSelection ( start, start );
1438 return;
1439 }
1440
1441 for ( iterator = start; iterator < end; iterator++ )
1442 {
1443 if ( !canMoveRightAt ( iterator ) )
1444 break;
1445 }
1446 SetSelection ( start, iterator );
1447 }
1448
setColorScheme(int scheme)1449 void XmlCtrl::setColorScheme ( int scheme )
1450 {
1451 StyleSetFaceName ( wxSTC_STYLE_DEFAULT, properties.font );
1452
1453 switch ( scheme )
1454 {
1455 case COLOR_SCHEME_DEFAULT:
1456 StyleSetForeground ( wxSTC_STYLE_DEFAULT, *wxBLACK );
1457 StyleSetBackground ( wxSTC_STYLE_DEFAULT, *wxWHITE );
1458 StyleClearAll();
1459
1460 baseBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 75 );
1461 alternateBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 95 );
1462 SetCaretLineBackground ( baseBackground );
1463
1464 SetCaretForeground ( *wxBLACK );
1465 SetSelBackground ( true, LightColour ( wxTheColourDatabase->Find ( _T ( "YELLOW" ) ), 20));//wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1466
1467 if ( type == FILE_TYPE_CSS )
1468 {
1469 // CSS colours
1470 StyleSetForeground ( wxSTC_CSS_DEFAULT, *wxBLACK );
1471 StyleSetForeground ( wxSTC_CSS_TAG, *wxBLUE );
1472 StyleSetForeground ( wxSTC_CSS_CLASS, *wxBLUE );
1473 StyleSetForeground ( wxSTC_CSS_PSEUDOCLASS, *wxBLUE );
1474 StyleSetForeground ( wxSTC_CSS_UNKNOWN_PSEUDOCLASS, *wxBLUE );
1475 StyleSetForeground ( wxSTC_CSS_OPERATOR, *wxBLUE );
1476 StyleSetForeground ( wxSTC_CSS_IDENTIFIER, *wxBLUE );
1477
1478 StyleSetForeground ( wxSTC_CSS_UNKNOWN_IDENTIFIER, *wxBLUE );
1479 StyleSetForeground ( wxSTC_CSS_VALUE, *wxBLACK );
1480 StyleSetForeground ( wxSTC_CSS_COMMENT,
1481 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1482 StyleSetForeground ( wxSTC_CSS_ID, *wxBLACK );
1483 StyleSetForeground ( wxSTC_CSS_IMPORTANT, *wxRED );
1484 StyleSetForeground ( wxSTC_CSS_DIRECTIVE, *wxBLUE );
1485 StyleSetForeground ( wxSTC_CSS_DOUBLESTRING, *wxRED );
1486 StyleSetForeground ( wxSTC_CSS_SINGLESTRING, *wxRED );
1487 StyleSetForeground ( wxSTC_CSS_IDENTIFIER2, *wxRED );
1488 StyleSetForeground ( wxSTC_CSS_ATTRIBUTE, *wxBLUE );
1489 }
1490 else // XML
1491 {
1492 StyleSetForeground ( wxSTC_H_DEFAULT, *wxBLACK );
1493 StyleSetForeground ( wxSTC_H_TAG, *wxBLUE );
1494 StyleSetForeground ( wxSTC_H_TAGUNKNOWN, *wxBLUE );
1495 StyleSetForeground ( wxSTC_H_ATTRIBUTE, *wxRED );
1496 StyleSetForeground ( wxSTC_H_ATTRIBUTEUNKNOWN, *wxRED );
1497 StyleSetForeground ( wxSTC_H_NUMBER, *wxBLACK );
1498 StyleSetForeground ( wxSTC_H_DOUBLESTRING, *wxBLACK );
1499 StyleSetForeground ( wxSTC_H_SINGLESTRING, *wxBLACK );
1500 StyleSetForeground ( wxSTC_H_OTHER, *wxBLUE );
1501 StyleSetForeground ( wxSTC_H_COMMENT,
1502 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1503 StyleSetForeground ( wxSTC_H_ENTITY, *wxRED );
1504 StyleSetForeground ( wxSTC_H_TAGEND, *wxBLUE );
1505 StyleSetForeground ( wxSTC_H_XMLSTART,
1506 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1507 StyleSetForeground ( wxSTC_H_XMLEND,
1508 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1509 StyleSetForeground ( wxSTC_H_CDATA, *wxRED );
1510 StyleSetForeground ( wxSTC_H_QUESTION,
1511 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1512
1513 for ( int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++ )
1514 StyleSetForeground ( i, *wxBLUE );
1515 StyleSetForeground ( wxSTC_H_SGML_ENTITY, *wxRED );
1516 StyleSetForeground ( wxSTC_H_SGML_SPECIAL, *wxBLACK );
1517 StyleSetForeground ( wxSTC_H_SGML_SIMPLESTRING, *wxRED );
1518 StyleSetForeground ( wxSTC_H_SGML_DEFAULT,
1519 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1520 }
1521 break;
1522 case COLOR_SCHEME_DEFAULT_BACKGROUND:
1523 StyleSetForeground ( wxSTC_STYLE_DEFAULT, *wxBLACK );
1524 StyleSetBackground ( wxSTC_STYLE_DEFAULT, *wxWHITE );
1525 StyleClearAll();
1526
1527 baseBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 75 );
1528 alternateBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 95 );
1529 SetCaretLineBackground ( baseBackground );
1530
1531 SetCaretForeground ( *wxBLACK );
1532 SetSelBackground ( true, LightColour ( wxTheColourDatabase->Find ( _T ( "YELLOW" ) ), 20) );//wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1533
1534 if ( type == FILE_TYPE_CSS )
1535 {
1536 // CSS colours
1537 StyleSetForeground ( wxSTC_CSS_DEFAULT, *wxBLACK );
1538 StyleSetForeground ( wxSTC_CSS_TAG,
1539 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1540 StyleSetForeground ( wxSTC_CSS_CLASS,
1541 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1542 StyleSetForeground ( wxSTC_CSS_PSEUDOCLASS,
1543 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1544 StyleSetForeground ( wxSTC_CSS_UNKNOWN_PSEUDOCLASS,
1545 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1546 StyleSetForeground ( wxSTC_CSS_OPERATOR,
1547 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1548 StyleSetForeground ( wxSTC_CSS_IDENTIFIER,
1549 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1550
1551 StyleSetForeground ( wxSTC_CSS_UNKNOWN_IDENTIFIER,
1552 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1553 StyleSetForeground ( wxSTC_CSS_VALUE, *wxBLACK );
1554 StyleSetForeground ( wxSTC_CSS_COMMENT,
1555 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1556 StyleSetForeground ( wxSTC_CSS_ID, *wxBLACK );
1557 StyleSetForeground ( wxSTC_CSS_IMPORTANT,
1558 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1559 StyleSetForeground ( wxSTC_CSS_DIRECTIVE,
1560 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1561 StyleSetForeground ( wxSTC_CSS_DOUBLESTRING,
1562 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1563 StyleSetForeground ( wxSTC_CSS_SINGLESTRING,
1564 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1565 StyleSetForeground ( wxSTC_CSS_IDENTIFIER2,
1566 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1567 StyleSetForeground ( wxSTC_CSS_ATTRIBUTE,
1568 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1569 }
1570 else // XML
1571 {
1572 StyleSetForeground ( wxSTC_H_DEFAULT, *wxBLACK );
1573 StyleSetForeground ( wxSTC_H_TAG,
1574 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1575 StyleSetForeground ( wxSTC_H_TAGUNKNOWN,
1576 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1577 StyleSetForeground ( wxSTC_H_ATTRIBUTE,
1578 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1579 StyleSetForeground ( wxSTC_H_ATTRIBUTEUNKNOWN,
1580 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1581 StyleSetForeground ( wxSTC_H_NUMBER,
1582 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1583 StyleSetForeground ( wxSTC_H_DOUBLESTRING,
1584 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1585 StyleSetForeground ( wxSTC_H_SINGLESTRING,
1586 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1587 StyleSetForeground ( wxSTC_H_OTHER,
1588 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1589 StyleSetForeground ( wxSTC_H_COMMENT,
1590 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1591 StyleSetForeground ( wxSTC_H_ENTITY,
1592 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1593 StyleSetForeground ( wxSTC_H_TAGEND,
1594 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1595 StyleSetForeground ( wxSTC_H_XMLSTART,
1596 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1597 StyleSetForeground ( wxSTC_H_XMLEND,
1598 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1599 StyleSetForeground ( wxSTC_H_CDATA,
1600 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1601 StyleSetForeground ( wxSTC_H_QUESTION,
1602 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1603
1604 for ( int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++ )
1605 StyleSetForeground ( i, wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1606 StyleSetForeground ( wxSTC_H_SGML_ENTITY,
1607 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1608 StyleSetForeground ( wxSTC_H_SGML_SPECIAL, *wxBLACK );
1609 StyleSetForeground ( wxSTC_H_SGML_SIMPLESTRING,
1610 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1611 StyleSetForeground ( wxSTC_H_SGML_DEFAULT,
1612 wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1613 }
1614 break;
1615 case COLOR_SCHEME_REDUCED_GLARE:
1616 StyleSetForeground ( wxSTC_STYLE_DEFAULT,
1617 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1618 StyleSetBackground ( wxSTC_STYLE_DEFAULT,
1619 wxTheColourDatabase->Find ( _T ( "MIDNIGHT BLUE" ) ) );
1620 StyleClearAll();
1621
1622 baseBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "NAVY" ) ), 0 );
1623 alternateBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "NAVY" ) ), 10 );
1624 SetCaretLineBackground ( baseBackground );
1625
1626 StyleSetForeground ( wxSTC_STYLE_LINENUMBER, *wxBLACK );
1627
1628 SetCaretForeground ( *wxWHITE );
1629 SetSelBackground ( true, wxTheColourDatabase->Find ( _T ( "GREY" ) ) );
1630
1631 if ( type == FILE_TYPE_CSS )
1632 {
1633 // CSS colours
1634 StyleSetForeground ( wxSTC_CSS_DEFAULT,
1635 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1636 StyleSetForeground ( wxSTC_CSS_TAG,
1637 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1638 StyleSetForeground ( wxSTC_CSS_CLASS,
1639 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1640 StyleSetForeground ( wxSTC_CSS_PSEUDOCLASS,
1641 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1642 StyleSetForeground ( wxSTC_CSS_UNKNOWN_PSEUDOCLASS,
1643 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1644 StyleSetForeground ( wxSTC_CSS_OPERATOR,
1645 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1646 StyleSetForeground ( wxSTC_CSS_IDENTIFIER,
1647 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1648
1649 StyleSetForeground ( wxSTC_CSS_UNKNOWN_IDENTIFIER,
1650 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1651 StyleSetForeground ( wxSTC_CSS_VALUE, *wxWHITE );
1652 StyleSetForeground ( wxSTC_CSS_COMMENT,
1653 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1654 StyleSetForeground ( wxSTC_CSS_ID, *wxWHITE );
1655 StyleSetForeground ( wxSTC_CSS_IMPORTANT,
1656 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1657 StyleSetForeground ( wxSTC_CSS_DIRECTIVE,
1658 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1659 StyleSetForeground ( wxSTC_CSS_DOUBLESTRING,
1660 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1661 StyleSetForeground ( wxSTC_CSS_SINGLESTRING,
1662 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1663 StyleSetForeground ( wxSTC_CSS_IDENTIFIER2,
1664 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1665 StyleSetForeground ( wxSTC_CSS_ATTRIBUTE,
1666 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1667 }
1668 else // XML
1669 {
1670 StyleSetForeground ( wxSTC_H_DEFAULT, *wxWHITE );
1671 StyleSetForeground ( wxSTC_H_TAG,
1672 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1673 StyleSetForeground ( wxSTC_H_TAGUNKNOWN,
1674 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1675 StyleSetForeground ( wxSTC_H_ATTRIBUTE,
1676 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1677 StyleSetForeground ( wxSTC_H_ATTRIBUTEUNKNOWN,
1678 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1679 StyleSetForeground ( wxSTC_H_NUMBER,
1680 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1681 StyleSetForeground ( wxSTC_H_DOUBLESTRING,
1682 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1683 StyleSetForeground ( wxSTC_H_SINGLESTRING,
1684 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1685 StyleSetForeground ( wxSTC_H_OTHER,
1686 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1687 StyleSetForeground ( wxSTC_H_COMMENT,
1688 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1689 StyleSetForeground ( wxSTC_H_ENTITY,
1690 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1691 StyleSetForeground ( wxSTC_H_TAGEND,
1692 wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1693 StyleSetForeground ( wxSTC_H_XMLSTART,
1694 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1695 StyleSetForeground ( wxSTC_H_XMLEND,
1696 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1697 StyleSetForeground ( wxSTC_H_CDATA,
1698 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1699 StyleSetForeground ( wxSTC_H_QUESTION,
1700 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1701
1702 for ( int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++ )
1703 StyleSetForeground ( i, wxTheColourDatabase->Find ( _T ( "SKY BLUE" ) ) );
1704 StyleSetForeground ( wxSTC_H_SGML_ENTITY,
1705 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1706 StyleSetForeground ( wxSTC_H_SGML_SPECIAL, *wxWHITE );
1707 StyleSetForeground ( wxSTC_H_SGML_SIMPLESTRING,
1708 wxTheColourDatabase->Find ( _T ( "ORANGE" ) ) );
1709 StyleSetForeground ( wxSTC_H_SGML_DEFAULT,
1710 wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1711 }
1712 break;
1713 case COLOR_SCHEME_NONE:
1714 baseBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 75 );
1715 alternateBackground = LightColour ( wxTheColourDatabase->Find ( _T ( "CYAN" ) ), 95 );
1716 SetCaretLineBackground ( baseBackground );
1717
1718 SetSelBackground ( true, wxTheColourDatabase->Find ( _T ( "LIGHT GREY" ) ) );
1719 SetCaretForeground ( *wxBLACK );
1720
1721 StyleSetForeground ( wxSTC_STYLE_DEFAULT, *wxBLACK );
1722 StyleSetBackground ( wxSTC_STYLE_DEFAULT, *wxWHITE );
1723 StyleClearAll();
1724
1725 break;
1726 default:
1727 break;
1728 }
1729 if ( type == FILE_TYPE_CSS )
1730 {
1731 StyleSetBold ( wxSTC_CSS_CLASS, true );
1732 StyleSetBold ( wxSTC_CSS_PSEUDOCLASS, true );
1733 StyleSetBold ( wxSTC_CSS_UNKNOWN_PSEUDOCLASS, true );
1734 StyleSetBold ( wxSTC_CSS_DOUBLESTRING, true );
1735 StyleSetBold ( wxSTC_CSS_SINGLESTRING, true );
1736 StyleSetBold ( wxSTC_CSS_DIRECTIVE, true );
1737 }
1738 else
1739 {
1740 StyleSetBold ( wxSTC_H_XMLSTART, true );
1741 StyleSetBold ( wxSTC_H_XMLEND, true );
1742 StyleSetBold ( wxSTC_H_ATTRIBUTEUNKNOWN, true );
1743 StyleSetBold ( wxSTC_H_ENTITY, true );
1744 StyleSetBold ( wxSTC_H_QUESTION, true );
1745 StyleSetBold ( wxSTC_H_SGML_ENTITY, true );
1746 StyleSetBold ( wxSTC_H_SGML_DEFAULT, true );
1747 }
1748
1749 wxColour color = wxSystemSettings::GetColour ( wxSYS_COLOUR_WINDOWTEXT );
1750 StyleSetForeground ( wxSTC_STYLE_LINENUMBER, color );
1751
1752 applyVisibilityState ( visibilityState );
1753 }
1754
applyVisibilityState(int state)1755 void XmlCtrl::applyVisibilityState ( int state )
1756 {
1757 if ( type == FILE_TYPE_BINARY )
1758 return;
1759
1760 visibilityState = state;
1761
1762 bool visible;
1763
1764 // hide tags/attributes
1765 visible = ( state == HIDE_ATTRIBUTES || state == HIDE_TAGS ) ? false : true;
1766 StyleSetVisible ( wxSTC_H_OTHER, visible );
1767 StyleSetVisible ( wxSTC_H_ATTRIBUTE, visible );
1768 StyleSetVisible ( wxSTC_H_ATTRIBUTEUNKNOWN, visible );
1769 StyleSetVisible ( wxSTC_H_DOUBLESTRING, visible );
1770 StyleSetVisible ( wxSTC_H_SINGLESTRING, visible );
1771
1772 // hide tags
1773 visible = ( state == HIDE_TAGS ) ? false : true;
1774 StyleSetVisible ( wxSTC_H_TAG, visible );
1775 StyleSetVisible ( wxSTC_H_TAGUNKNOWN, visible );
1776 StyleSetVisible ( wxSTC_H_TAGEND, visible );
1777
1778 StyleSetVisible ( wxSTC_H_XMLSTART, visible );
1779 StyleSetVisible ( wxSTC_H_XMLEND, visible );
1780 StyleSetVisible ( wxSTC_H_CDATA, visible );
1781 StyleSetVisible ( wxSTC_H_QUESTION, visible );
1782 StyleSetVisible ( wxSTC_H_COMMENT, visible );
1783 for ( int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++ )
1784 StyleSetVisible ( i, visible );
1785
1786 Colourise ( 0, -1 );
1787 }
1788
getType()1789 int XmlCtrl::getType()
1790 {
1791 return type;
1792 }
1793
foldAll()1794 void XmlCtrl::foldAll()
1795 {
1796 expandFoldsToLevel ( 1, false );
1797 }
1798
unfoldAll()1799 void XmlCtrl::unfoldAll()
1800 {
1801 expandFoldsToLevel ( wxSTC_FOLDLEVELNUMBERMASK, true );
1802 }
1803
toggleFold()1804 void XmlCtrl::toggleFold()
1805 {
1806 int pos, line, level;
1807 pos = GetCurrentPos();
1808 if ( pos == -1 )
1809 return;
1810 line = LineFromPosition ( pos );
1811 level = GetFoldLevel ( line );
1812
1813 for ( int iterator = line; iterator > 0; iterator-- )
1814 {
1815 if ( iterator != line )
1816 {
1817 GotoLine ( iterator );
1818 level = GetFoldLevel ( iterator );
1819 }
1820
1821 if ( XMLCTRL_HASBIT ( level, wxSTC_FOLDLEVELHEADERFLAG ) )
1822 {
1823 ToggleFold ( iterator );
1824 break;
1825 }
1826 }
1827 }
1828
1829 // adapted from wxSTEdit (c) 2005 John Labenski, Otto Wyss
expandFoldsToLevel(int level,bool expand)1830 void XmlCtrl::expandFoldsToLevel ( int level, bool expand )
1831 {
1832 Colourise ( 0, -1 );
1833
1834 const int line_n = GetLineCount();
1835 for ( int n = 0; n < line_n; n++ )
1836 {
1837 int line_level = GetFoldLevel ( n );
1838 if ( XMLCTRL_HASBIT ( line_level, wxSTC_FOLDLEVELHEADERFLAG ) )
1839 {
1840 line_level -= wxSTC_FOLDLEVELBASE;
1841 line_level &= wxSTC_FOLDLEVELNUMBERMASK;
1842
1843 if ( ( ( expand && ( line_level <= level ) ) ||
1844 ( !expand && ( line_level >= level ) ) ) && ( GetFoldExpanded ( n ) != expand ) )
1845 ToggleFold ( n );
1846 }
1847 }
1848
1849 EnsureCaretVisible(); // seems to keep it in nearly the same place
1850 }
1851
protectHeadLine()1852 void XmlCtrl::protectHeadLine()
1853 {
1854 if ( *protectTags || !properties.fold )
1855 return;
1856
1857 int pos1, pos2, line1, line2, level;
1858 pos1 = GetSelectionStart();
1859 pos2 = GetSelectionEnd();
1860 line1 = LineFromPosition ( pos1 );
1861 line2 = LineFromPosition ( pos2 );
1862
1863 if ( line2 < line1 )
1864 {
1865 int temp = line1;
1866 line1 = line2;
1867 line2 = temp;
1868 }
1869
1870 for ( int i = line1; i <= line2; i++ )
1871 {
1872 level = GetFoldLevel ( i );
1873 if ( XMLCTRL_HASBIT ( level, wxSTC_FOLDLEVELHEADERFLAG ) && !GetFoldExpanded ( i ) )
1874 ToggleFold ( i );
1875 }
1876 }
1877
getOpenTag(const wxString & element)1878 wxString XmlCtrl::getOpenTag ( const wxString& element )
1879 {
1880 wxString openTag;
1881 openTag = _T ( "<" ) + element;
1882 std::set<wxString> requiredAttributeSet;
1883 std::set<wxString>::iterator it;
1884 requiredAttributeSet = requiredAttributeMap[element];
1885 if ( !requiredAttributeSet.empty() )
1886 {
1887 for ( it = requiredAttributeSet.begin(); it != requiredAttributeSet.end(); ++it )
1888 {
1889 openTag += _T ( " " );
1890 openTag += *it;
1891 openTag += _T ( "=\"\"" );
1892 }
1893 }
1894 openTag += _T ( ">" );
1895 return openTag;
1896 }
1897
insertChild(const wxString & child)1898 bool XmlCtrl::insertChild ( const wxString& child )
1899 {
1900 int start, end;
1901 start = GetSelectionStart();
1902 end = GetSelectionEnd();
1903 int offset;
1904
1905 wxString openTag, closeTag;
1906
1907 openTag = getOpenTag ( child );
1908 closeTag = _T ( "</" ) + child + _T ( ">" );
1909
1910 if ( start == end )
1911 {
1912 if ( !canInsertAt ( start ) )
1913 return false;
1914 offset = openTag.Length();
1915
1916 wxString tag;
1917 tag = openTag + closeTag;
1918 InsertText ( start, tag );
1919 SetSelection ( start + offset, start + offset );
1920 SetFocus();
1921 return true;
1922 }
1923 if ( *protectTags )
1924 adjustSelection();
1925 offset = openTag.Length();
1926 if ( start > end )
1927 {
1928 int temp = end;
1929 start = end;
1930 end = temp;
1931 }
1932 InsertText ( start, openTag );
1933 InsertText ( end + offset, closeTag );
1934 SetSelection ( start + offset, end + offset );
1935 return true;
1936 }
1937
insertSibling(const wxString & sibling,const wxString & parent)1938 bool XmlCtrl::insertSibling ( const wxString& sibling, const wxString& parent )
1939 {
1940 int start = GetSelectionStart();
1941 int limit = GetLength();
1942 wxString parentCloseTag = _T ( "</" ) + parent + _T ( ">" );
1943 int parentCloseTagStart = FindText ( start, limit, parentCloseTag );
1944 if ( parentCloseTagStart == -1 ||
1945 !canInsertAt ( parentCloseTagStart + parentCloseTag.Length() ) )
1946 return false;
1947
1948 int insertionPoint = parentCloseTagStart + parentCloseTag.Length();
1949 SetSelection ( insertionPoint, insertionPoint );
1950 insertNewLine();
1951
1952 wxString openTag, closeTag;
1953 int newCurrentPos, newAdjustedPos;
1954 newCurrentPos = GetCurrentPos();
1955
1956 openTag = getOpenTag ( sibling );
1957 closeTag = _T ( "</" ) + sibling + _T ( ">" );
1958
1959 InsertText ( newCurrentPos, openTag + closeTag );
1960 newAdjustedPos = newCurrentPos + openTag.Length();
1961 SetSelection ( newAdjustedPos, newAdjustedPos );
1962 return true;
1963 }
1964
insertEntity(const wxString & entity)1965 bool XmlCtrl::insertEntity ( const wxString& entity )
1966 {
1967 if ( *protectTags )
1968 adjustCursor();
1969
1970 wxString insertBuffer;
1971 insertBuffer.Printf ( _T ( "&%s;" ), entity.c_str() );
1972 int pos = GetCurrentPos();
1973 InsertText ( GetCurrentPos(), insertBuffer );
1974 pos += insertBuffer.size();
1975 SetSelection ( pos, pos );
1976 return true;
1977 }
1978
getParent()1979 wxString XmlCtrl::getParent()
1980 {
1981 int current, parentCloseAngleBracket;
1982 current = GetCurrentPos();
1983 parentCloseAngleBracket = getParentCloseAngleBracket ( current );
1984 return getLastElementName ( parentCloseAngleBracket );
1985 }
1986
insertNewLine()1987 void XmlCtrl::insertNewLine()
1988 {
1989 bool autoindent = false;
1990 int pos, line, startPos, iteratorPos, newPos;
1991 pos = GetCurrentPos();
1992 line = LineFromPosition ( pos );
1993 startPos = PositionFromLine ( line );
1994 iteratorPos = startPos;
1995
1996 for ( iteratorPos = startPos;
1997 ( GetCharAt ( iteratorPos ) == ' ' ||
1998 GetCharAt ( iteratorPos ) == '\t' ) &&
1999 iteratorPos < pos;
2000 ++iteratorPos )
2001 autoindent = true;
2002 wxString s = GetTextRange ( startPos, iteratorPos );
2003 NewLine();
2004 if ( autoindent )
2005 {
2006 newPos = PositionFromLine ( line + 1 );
2007 InsertText ( newPos, s );
2008 SetSelection ( newPos + s.size(), newPos + s.size() );
2009 }
2010 }
2011
toggleLineBackground()2012 void XmlCtrl::toggleLineBackground()
2013 {
2014 if ( !properties.toggleLineBackground || visibilityState != HIDE_TAGS )
2015 {
2016 if ( lineBackgroundState != BACKGROUND_STATE_NORMAL )
2017 {
2018 SetCaretLineBackground ( baseBackground );
2019 lineBackgroundState = BACKGROUND_STATE_NORMAL;
2020 }
2021 return;
2022 }
2023 lineBackgroundState = ( lineBackgroundState == BACKGROUND_STATE_NORMAL ) ?
2024 BACKGROUND_STATE_LIGHT : BACKGROUND_STATE_NORMAL;
2025 SetCaretLineBackground ( ( lineBackgroundState == BACKGROUND_STATE_NORMAL ) ? baseBackground : alternateBackground );
2026 }
2027
getEntitySet()2028 const std::set<wxString> &XmlCtrl::getEntitySet()
2029 {
2030 return entitySet;
2031 }
2032
getAttributes(const wxString & parent)2033 const std::set<std::string> &XmlCtrl::getAttributes ( const wxString& parent )
2034 {
2035 static std::set<std::string> retVal;
2036 return retVal;
2037 }
2038
getElementStructure(const wxString & element)2039 wxString XmlCtrl::getElementStructure ( const wxString& element )
2040 {
2041 if ( elementStructureMap.find ( element ) == elementStructureMap.end() )
2042 {
2043 return wxEmptyString;
2044 }
2045 return elementStructureMap[element];
2046 }
2047
backgroundValidate()2048 bool XmlCtrl::backgroundValidate()
2049 {
2050 if ( !properties.validateAsYouType || type != FILE_TYPE_XML )
2051 return true;
2052
2053 std::string bufferUtf8 = myGetTextRaw();
2054
2055 return backgroundValidate (
2056 bufferUtf8.c_str(),
2057 basePath,
2058 bufferUtf8.size() );
2059 }
2060
backgroundValidate(const char * buffer,const wxString & system,size_t bufferLen)2061 bool XmlCtrl::backgroundValidate (
2062 const char *buffer,
2063 const wxString &system,
2064 size_t bufferLen
2065 )
2066 {
2067 if ( !validationRequired )
2068 return true;
2069
2070 wxCriticalSectionLocker locker ( xmlcopyeditorCriticalSection );
2071
2072 if ( validationThread != NULL )
2073 {
2074 return true; // wait for next idle cycle call from main app frame
2075 }
2076 validationRequired = false;
2077
2078 validationThread = new ValidationThread(
2079 GetEventHandler(),
2080 buffer,
2081 system
2082 );
2083
2084 if ( validationThread->Create() != wxTHREAD_NO_ERROR
2085 || validationThread->Run() != wxTHREAD_NO_ERROR )
2086 {
2087 delete validationThread;
2088 validationThread = NULL;
2089 return false;
2090 }
2091
2092 return true;
2093 }
2094
myGetTextRaw()2095 std::string XmlCtrl::myGetTextRaw()
2096 {
2097 return ( const char * ) GetTextRaw();
2098 }
2099
setErrorIndicator(int line,int column)2100 void XmlCtrl::setErrorIndicator ( int line, int column )
2101 {
2102 int startPos, endPos, endStyled;
2103 startPos = PositionFromLine ( line ) + column;
2104 endPos = GetLineEndPosition ( line );
2105 endStyled = GetEndStyled();
2106 if ( endPos > endStyled ) endPos = endStyled;
2107
2108 int length = endPos - startPos;
2109 if ( length > 0 && length + startPos < GetLength() )
2110 {
2111 #if wxCHECK_VERSION(2,9,0)
2112 IndicatorFillRange ( startPos, length );
2113 #else
2114 StartStyling ( startPos, wxSTC_INDIC2_MASK );
2115 SetStyling ( length, wxSTC_INDIC2_MASK );
2116 #endif
2117 }
2118 }
2119
clearErrorIndicators(int maxLine)2120 void XmlCtrl::clearErrorIndicators ( int maxLine )
2121 {
2122 if ( maxLine < 0 )
2123 return;
2124
2125 int length = GetLength();
2126 if ( !length )
2127 return;
2128
2129 int end = GetEndStyled();
2130 length = ( maxLine ) ? GetLineEndPosition ( maxLine ) : length;
2131 if ( end > 0 && length > end ) length = end;
2132
2133 #if wxCHECK_VERSION(2,9,0)
2134 IndicatorClearRange ( 0, length );
2135 #else
2136 StartStyling ( 0, wxSTC_INDIC2_MASK );
2137 SetStyling ( length, 0 );
2138 #endif
2139 }
2140
getValidationRequired()2141 bool XmlCtrl::getValidationRequired()
2142 {
2143 return validationRequired;
2144 }
2145
setValidationRequired(bool b)2146 void XmlCtrl::setValidationRequired ( bool b )
2147 {
2148 validationRequired = b;
2149 }
2150
getTagType(int pos)2151 int XmlCtrl::getTagType ( int pos )
2152 {
2153 int iteratorPos;
2154
2155 // preliminary checks
2156 if ( pos < 2 )
2157 {
2158 return TAG_TYPE_ERROR;
2159 }
2160 else if ( GetCharAt ( pos - 1 ) == '/' )
2161 {
2162 return TAG_TYPE_EMPTY;
2163 }
2164
2165 // go to start of tag
2166 for ( iteratorPos = pos; iteratorPos >= 0; --iteratorPos )
2167 {
2168 int style = getLexerStyleAt ( iteratorPos );
2169 //style &= ~wxSTC_INDIC2_MASK;
2170
2171 if ( GetCharAt ( iteratorPos ) == '<' &&
2172 ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN ) )
2173 break;
2174 }
2175 if ( GetCharAt ( iteratorPos ) != '<' )
2176 return TAG_TYPE_ERROR;
2177
2178 char c = GetCharAt ( iteratorPos + 1 );
2179 if ( c == '!' || c == '?' )
2180 return TAG_TYPE_OTHER;
2181 else if ( c == '/' )
2182 {
2183 return TAG_TYPE_CLOSE;
2184 }
2185 else
2186 {
2187 return TAG_TYPE_OPEN;
2188 }
2189 }
2190
2191 // fetch style int disregarding indicator
getLexerStyleAt(int pos)2192 int XmlCtrl::getLexerStyleAt ( int pos )
2193 {
2194 int style = GetStyleAt ( pos );
2195 #if !wxCHECK_VERSION(2,9,0)
2196 style &= ~wxSTC_INDIC2_MASK;
2197 #endif
2198 return style;
2199 }
2200
getGrammarFound()2201 bool XmlCtrl::getGrammarFound()
2202 {
2203 return grammarFound;
2204 }
2205
OnMiddleDown(wxMouseEvent & event)2206 void XmlCtrl::OnMiddleDown ( wxMouseEvent& event )
2207 {
2208 if ( GetSelectionStart() == GetSelectionEnd() )
2209 {
2210 event.Skip();
2211 return;
2212 }
2213 Copy();
2214 long x, y;
2215 event.GetPosition ( &x, &y );
2216 int pastePosition = PositionFromPointClose ( x, y );
2217 if ( pastePosition == wxSTC_INVALID_POSITION )
2218 {
2219 event.Skip();
2220 return;
2221 }
2222 SetSelection ( pastePosition, pastePosition );
2223 Paste();
2224 }
2225
selectCurrentElement()2226 bool XmlCtrl::selectCurrentElement()
2227 {
2228 if ( type != FILE_TYPE_XML )
2229 return false;
2230
2231 Colourise ( 0, -1 );
2232
2233 int pos = GetCurrentPos();
2234 int style = getLexerStyleAt ( pos ) ;
2235 if ( style == wxSTC_H_COMMENT )
2236 {
2237 int i = pos;
2238 while ( --i >= 0 && getLexerStyleAt ( i ) == wxSTC_H_COMMENT )
2239 continue;
2240 SetSelectionStart ( i + 1 );
2241
2242 int styled = GetEndStyled();
2243 i = pos;
2244 while ( i < styled && getLexerStyleAt ( i ) == wxSTC_H_COMMENT )
2245 i++;
2246 SetSelectionEnd ( i );
2247 }
2248 else
2249 {
2250 // Select current tag
2251 int start = findPreviousStartTag ( pos, 1, '<', pos );
2252 if ( start < 0 )
2253 {
2254 MyFrame *frame = ( MyFrame * ) wxTheApp->GetTopWindow();
2255 frame->statusProgress ( _("Cannot find the start tag") );
2256 return false;
2257 }
2258 int range = GetTextLength() - pos;
2259 int end = findNextEndTag ( pos, 1, '>', range );
2260 if ( end < 0 )
2261 {
2262 MyFrame *frame = ( MyFrame * ) wxTheApp->GetTopWindow();
2263 frame->statusProgress ( _("Cannot find the end tag") );
2264 return false;
2265 }
2266 SetSelection ( start, end );
2267 }
2268
2269 return true;
2270 }
2271
toggleComment()2272 void XmlCtrl::toggleComment()
2273 {
2274 MyFrame *frame = ( MyFrame * ) wxTheApp->GetTopWindow();
2275 frame->statusProgress ( wxEmptyString );
2276
2277 int pos = -1;
2278 wxString commentStart = _T ( "<!--" );
2279 wxString commentEnd = _T ( "-->" );
2280
2281 // Is there a selection?
2282 int from = GetSelectionStart();
2283 int to = GetSelectionEnd();
2284 switch ( type )
2285 {
2286 case FILE_TYPE_BINARY:
2287 return;
2288
2289 case FILE_TYPE_CSS:
2290 if ( from == to )
2291 return;
2292
2293 commentStart = _T ( "/*" );
2294 commentEnd = _T ( "*/" );
2295 break;
2296
2297 case FILE_TYPE_XML:
2298 if ( from != to )
2299 break;
2300
2301 // Select current element
2302 pos = GetCurrentPos();
2303 if ( !selectCurrentElement() )
2304 return;
2305 break;
2306
2307 default:
2308 if ( from == to )
2309 return;
2310 break;
2311 }
2312
2313 wxString text = GetSelectedText();
2314 wxASSERT ( !text.IsEmpty() );
2315
2316 // Skip leading spaces
2317 wxString::iterator itr, start, end;
2318 itr = start = text.begin();
2319 end = text.end();
2320 while ( itr != end && wxIsspace ( *itr ) )
2321 ++itr;
2322
2323 size_t startPos = itr - start;
2324 int ret = text.compare ( startPos, commentStart.length(), commentStart );
2325 if ( ret == 0 )
2326 {
2327 start = itr;
2328 itr = end;
2329 do {
2330 --itr;
2331 } while ( itr != start && wxIsspace ( *itr ) );
2332
2333 size_t endPos = itr - start;
2334 if ( endPos > commentEnd.length() )
2335 {
2336 endPos = itr - text.begin() - commentEnd.length() + 1;
2337 ret = text.compare ( endPos, commentEnd.length(), commentEnd );
2338
2339 // Is commented?
2340 if ( ret == 0 )
2341 {
2342 text.erase ( endPos, commentEnd.length() );
2343 text.erase ( startPos, commentStart.length() );
2344
2345 ReplaceSelection ( text );
2346 pos -= commentStart.length();
2347 if ( pos >= 0 )
2348 SetSelection ( pos, pos );
2349 return;
2350 }
2351 }
2352 }
2353
2354 // Comment selection
2355
2356 // "--" is not allowed in comments
2357 if ( commentStart == _T ( "<!--" ) )
2358 {
2359 const static wxString doubleHyphen = _T ( "--" );
2360 size_t offset = 0;
2361 while ( ( offset = text.find ( doubleHyphen, offset ) ) != wxString::npos )
2362 {
2363 text.replace ( offset, doubleHyphen.length(), _T ( "- -" ) );
2364 offset += 2; // WARNING: Not three!
2365 }
2366 }
2367
2368 text = commentStart + text + commentEnd;
2369
2370 ReplaceSelection ( text );
2371 if ( pos >= 0 )
2372 {
2373 pos += commentStart.length();
2374 SetSelection ( pos, pos );
2375 }
2376 }
2377
getCurrentXPath()2378 wxString XmlCtrl::getCurrentXPath()
2379 {
2380 wxString xpath;
2381 int pos = GetCurrentPos();
2382 for ( ; ; )
2383 {
2384 pos = findPreviousStartTag ( pos, 1, '>' );
2385 if ( pos <= 0 )
2386 break;
2387
2388 wxString name = getLastElementName ( pos );
2389 size_t pos = name.Index ( ':' );
2390 if ( pos != wxString::npos && pos < name.length() )
2391 {
2392 ++pos;
2393 name = _T("*[local-name()='")
2394 + name.substr ( pos, name.length() - pos ) + _T("']");
2395 }
2396 xpath = _T("/") + name + xpath;
2397 }
2398
2399 return xpath;
2400 }
2401
OnKillFocus(wxFocusEvent & event)2402 void XmlCtrl::OnKillFocus ( wxFocusEvent &event )
2403 {
2404 AutoCompCancel();
2405 event.Skip();
2406 }
2407
getPrevNonSpaceChar(int curPos,int * charPos)2408 int XmlCtrl::getPrevNonSpaceChar ( int curPos, int *charPos )
2409 {
2410 int c = 0;
2411 int pos = curPos;
2412 while ( pos-- > 0 )
2413 {
2414 c = GetCharAt ( pos );
2415 if ( !wxIsspace ( c ) )
2416 break;
2417 }
2418
2419 if ( charPos )
2420 *charPos = pos;
2421
2422 return c;
2423 }
2424