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 ( "&lt;" ) );
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 ( "&gt;" ) );
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 ( "&amp;" ) );
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