Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / action_handler_edit.cpp
blob1f3b7ee4f390c10b0ff83de4f654d195c4de0061
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "stdpch.h"
26 using namespace std;
27 using namespace NLMISC;
29 #include "nel/gui/action_handler.h"
30 #include "nel/gui/group_editbox.h"
31 #include "nel/misc/utf_string_view.h"
32 #include "interface_manager.h"
33 #include "../client_chat_manager.h"
34 #include "people_interraction.h"
35 #include "../r2/editor.h"
36 /*#include "user_controls.h"
37 #include "view.h"
38 #include "misc.h"
39 #include "input.h"*/
41 ////////////
42 // EXTERN //
43 ////////////
45 extern CClientChatManager ChatMngr;
48 ////////////
49 // GLOBAL //
50 ////////////
52 /**********************************************************************************************************
53 * *
54 * edit handlers actions *
55 * *
56 ***********************************************************************************************************/
58 // ***************************************************************************
60 // used for character classifiction (when the user press Ctrl-arrow)
61 static inline uint getCharacterCategory(u32char c)
63 if (c == ' ') return 0;
64 if (c > 127 || isalpha((char) c)) return 1; // alpha & other characters
65 if (isdigit((char) c)) return 2;
66 return 3; // other cases, including punctuation
69 // ***************************************************************************
71 /** skip a block of character in a string, (same behaviour than when Ctrl-arrow is pressed)
72 * It returns the new index
74 static uint skipUCCharsRight(uint startPos, const ::u32string &str)
76 uint pos = startPos;
77 uint endIndex = (uint)str.length();
78 uint ccat = getCharacterCategory(str[pos]);
79 // skip characters of the same category
80 while (pos != endIndex && getCharacterCategory(str[pos]) == ccat) ++pos;
81 // skip spaces
82 while (pos != endIndex && str[pos] == ' ') ++pos;
83 return pos;
86 // ***************************************************************************
88 /** skip a block of character in a string, (same behaviour than when Ctrl-arrow is pressed)
89 * It returns the new index
91 static uint skipUCCharsLeft(uint startPos, const ::u32string &str)
93 uint pos = startPos;
94 -- pos;
95 while (pos != 0 && str[pos] == ' ') --pos;
96 if (pos == 0) return pos;
97 uint ccat = getCharacterCategory(str[pos]);
98 // skip characters of the same category
99 while (pos != 0 && getCharacterCategory(str[pos - 1]) == ccat) --pos;
100 return pos;
103 // ***************************************************************************
105 class CAHEdit : public IActionHandler
107 protected:
108 // Current edit box. Filled by init.
109 CGroupEditBox *_GroupEdit;
110 bool _LooseSelection;
112 // Init the action manager
113 void init ()
115 // Get the current edit box
116 _GroupEdit = NULL;
117 _LooseSelection = false;
119 // Get the interface manager
120 CInterfaceManager *pIM = CInterfaceManager::getInstance();
121 if (pIM)
123 CCtrlBase *basectrl = CWidgetManager::getInstance()->getCaptureKeyboard();
124 if (basectrl)
125 _GroupEdit = dynamic_cast<CGroupEditBox*>(basectrl);
128 if (_GroupEdit)
129 _GroupEdit->stopParentBlink();
132 // For action handler that modify selection
133 void handleSelection ()
135 if (_GroupEdit)
137 // If selection not active
138 if (CGroupEditBox::getCurrSelection() == NULL)
140 // then start selection at curPos
141 CGroupEditBox::setSelectCursorPos(_GroupEdit->getCursorPos());
142 CGroupEditBox::setCurrSelection (_GroupEdit);
147 // For action handler that unselect
148 void handleUnselection()
150 if (_GroupEdit)
152 // If selection active
153 CGroupEditBox *currSelection = dynamic_cast< CGroupEditBox* >( CGroupEditBox::getCurrSelection() );
154 if (currSelection != NULL)
156 if (currSelection != _GroupEdit)
158 nlwarning("Selection can only be on focus");
161 // disable selection
162 CGroupEditBox::setCurrSelection(NULL);
163 _LooseSelection = true;
168 // Init part
169 virtual void initPart ()
171 init();
172 handleUnselection();
175 // Action part
176 virtual void actionPart () = 0;
178 // R2 editor part (no op by default)
179 virtual void forwardToEditor() {}
181 // Tha action handler
182 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
184 initPart ();
185 if (_GroupEdit)
187 actionPart ();
189 else
191 forwardToEditor();
196 // ***************************************************************************
198 class CAHEditPreviousChar : public CAHEdit
200 void actionPart ()
202 if (_LooseSelection)
204 sint32 minPos= min(_GroupEdit->getCursorPos(), _GroupEdit->getSelectCursorPos());
205 sint32 maxPos= max(_GroupEdit->getCursorPos(), _GroupEdit->getSelectCursorPos());
207 // Special Code if left or right: Set the cursor pos to bounds of selection.
208 if(minPos!=maxPos)
210 _GroupEdit->setCursorPos(minPos);
211 // don't call std Left
212 return;
216 if (_GroupEdit->getCursorPos() > 0)
218 _GroupEdit->setCursorPos(_GroupEdit->getCursorPos()-1);
219 _GroupEdit->setCursorAtPreviousLineEnd(false);
223 REGISTER_ACTION_HANDLER (CAHEditPreviousChar, "edit_previous_char");
225 // ***************************************************************************
227 class CAHEditNextChar : public CAHEdit
229 void actionPart ()
231 if (_LooseSelection)
233 sint32 minPos = min(_GroupEdit->getCursorPos(), _GroupEdit->getSelectCursorPos());
234 sint32 maxPos = max(_GroupEdit->getCursorPos(), _GroupEdit->getSelectCursorPos());
236 if(minPos!=maxPos)
238 _GroupEdit->setCursorPos(maxPos);
239 // don't call std Right
240 return;
244 if (_GroupEdit->getCursorPos() < (sint32) _GroupEdit->getInputStringRef().length())
246 _GroupEdit->setCursorPos(_GroupEdit->getCursorPos()+1);
247 _GroupEdit->setCursorAtPreviousLineEnd(false);
251 REGISTER_ACTION_HANDLER (CAHEditNextChar, "edit_next_char");
253 // ***************************************************************************
255 class CAHEditPreviousWord : public CAHEdit
257 void actionPart ()
259 if (_GroupEdit->getCursorPos() > 0)
261 _GroupEdit->setCursorPos(skipUCCharsLeft(_GroupEdit->getCursorPos(), _GroupEdit->getInputStringRef()));
262 _GroupEdit->setCursorAtPreviousLineEnd(false);
266 REGISTER_ACTION_HANDLER (CAHEditPreviousWord, "edit_previous_word");
268 // ***************************************************************************
270 class CAHEditNextWord : public CAHEdit
272 void actionPart ()
274 if (_GroupEdit->getCursorPos() < (sint32) _GroupEdit->getInputStringRef().length())
276 _GroupEdit->setCursorPos(skipUCCharsRight(_GroupEdit->getCursorPos(), _GroupEdit->getInputStringRef()));
277 _GroupEdit->setCursorAtPreviousLineEnd(false);
281 REGISTER_ACTION_HANDLER (CAHEditNextWord, "edit_next_word");
283 // ***************************************************************************
285 class CAHEditGotoLineBegin : public CAHEdit
287 void actionPart ()
289 // go to the start of line
290 if (_GroupEdit->getViewText())
292 sint line = _GroupEdit->getViewText()->getLineFromIndex(_GroupEdit->getCursorPos() + (uint)_GroupEdit->getPromptRef().length());
293 if (line == -1) return;
294 sint newPos = std::max(_GroupEdit->getViewText()->getLineStartIndex(line), (sint) _GroupEdit->getPromptRef().length());
295 if (newPos == -1) return;
296 _GroupEdit->setCursorPos(newPos - (sint32)_GroupEdit->getPromptRef().length());
297 _GroupEdit->setCursorAtPreviousLineEnd(false);
301 REGISTER_ACTION_HANDLER (CAHEditGotoLineBegin, "edit_goto_line_begin");
303 // ***************************************************************************
305 class CAHEditGotoLineEnd : public CAHEdit
307 void actionPart ()
309 // go to the end of line
310 if (_GroupEdit->getViewText())
312 if (_GroupEdit->getViewText()->getMultiLine())
314 sint line = _GroupEdit->getViewText()->getLineFromIndex(_GroupEdit->getCursorPos() + (uint)_GroupEdit->getPromptRef().length(), _GroupEdit->isCursorAtPreviousLineEnd());
315 if (line == -1) return;
316 sint newPos;
317 bool endOfPreviousLine;
318 _GroupEdit->getViewText()->getLineEndIndex(line, newPos, endOfPreviousLine);
319 if (newPos != -1)
321 _GroupEdit->setCursorPos(newPos - (sint32)_GroupEdit->getPromptRef().length());
322 _GroupEdit->setCursorAtPreviousLineEnd(endOfPreviousLine);
325 else
327 _GroupEdit->setCursorPos((sint32)_GroupEdit->getPromptRef().length() + (sint32)_GroupEdit->getInputString().length());
332 REGISTER_ACTION_HANDLER (CAHEditGotoLineEnd, "edit_goto_line_end");
334 // ***************************************************************************
336 class CAHEditGotoBlockBegin : public CAHEdit
338 void actionPart ()
340 _GroupEdit->setCursorPos(0);
341 _GroupEdit->setCursorAtPreviousLineEnd(false);
344 REGISTER_ACTION_HANDLER (CAHEditGotoBlockBegin, "edit_goto_block_begin");
346 // ***************************************************************************
348 class CAHEditGotoBlockEnd : public CAHEdit
350 void actionPart ()
352 _GroupEdit->setCursorPos((sint32)_GroupEdit->getInputStringRef().length());
353 _GroupEdit->setCursorAtPreviousLineEnd(false);
356 REGISTER_ACTION_HANDLER (CAHEditGotoBlockEnd, "edit_goto_block_end");
358 // ***************************************************************************
360 class CAHEditPreviousLine : public CAHEdit
362 void actionPart ()
364 if (_GroupEdit->getMaxHistoric() && (! _GroupEdit->getViewText()->getMultiLine()))
366 // Get the start of the string.
367 ::u32string startStr= _GroupEdit->getInputStringRef().substr(0, _GroupEdit->getCursorPos());
369 // Search all historic string that match startStr.
370 for(sint i=_GroupEdit->getCurrentHistoricIndex()+1;i<(sint)_GroupEdit->getNumHistoric();i++)
372 if( _GroupEdit->getHistoric(i).compare(0, _GroupEdit->getCursorPos(), startStr)==0 )
374 _GroupEdit->setInputStringRef (_GroupEdit->getHistoric(i));
375 _GroupEdit->setCurrentHistoricIndex(i);
376 break;
380 else if (_GroupEdit->getViewText()->getMultiLine())
382 uint cursorPosInText = _GroupEdit->getCursorPos() + (uint)_GroupEdit->getPromptRef().length();
383 if (
384 (_GroupEdit->getCursorPos() == (sint32) _GroupEdit->getInputStringRef().length() && _GroupEdit->getViewText()->getNumLine() == 1) ||
385 _GroupEdit->getViewText()->getLineFromIndex(cursorPosInText, _GroupEdit->isCursorAtPreviousLineEnd()) == 0
386 ) // in the first line .. ?
388 // .. so do nothing
389 return;
391 float cx, cy;
392 float height;
393 _GroupEdit->getViewText()->getCharacterPositionFromIndex(cursorPosInText, _GroupEdit->isCursorAtPreviousLineEnd(), cx, cy, height);
394 cy += _GroupEdit->getViewText()->getLineHeight();
395 uint newCharIndex;
396 bool newLineEnd;
397 _GroupEdit->getViewText()->getCharacterIndexFromPosition(cx, cy, newCharIndex, newLineEnd);
398 if (newLineEnd)
400 _GroupEdit->setCursorPos(newCharIndex - (sint32)_GroupEdit->getPromptRef().length());
401 _GroupEdit->setCursorAtPreviousLineEnd(true);
402 sint32 newPos = _GroupEdit->getCursorPos();
403 clamp(newPos, (sint32) 0, (sint32) _GroupEdit->getInputStringRef().size());
404 _GroupEdit->setCursorPos(newPos);
405 return;
407 _GroupEdit->setCursorAtPreviousLineEnd(false);
408 // takes character whose X is closer to the current X
409 float cx0, cx1;
410 float cy0, cy1;
411 _GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex, _GroupEdit->isCursorAtPreviousLineEnd(), cx0, cy0, height);
412 _GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex + 1, _GroupEdit->isCursorAtPreviousLineEnd(), cx1, cy1, height);
413 if (abs(cx0 - cx) < abs(cx1 - cx) || cy0 != cy1)
415 _GroupEdit->setCursorPos(newCharIndex);
417 else
419 _GroupEdit->setCursorPos(newCharIndex + 1);
421 _GroupEdit->setCursorPos(_GroupEdit->getCursorPos()-(sint32)_GroupEdit->getPromptRef().length());
422 sint32 newpos = _GroupEdit->getCursorPos();
423 clamp(newpos, (sint32) 0, (sint32)_GroupEdit->getInputStringRef().size());
424 _GroupEdit->setCursorPos(newpos);
428 REGISTER_ACTION_HANDLER (CAHEditPreviousLine, "edit_previous_line");
430 // ***************************************************************************
432 class CAHEditNextLine : public CAHEdit
434 void actionPart ()
436 if( (! _GroupEdit->getViewText()->getMultiLine()) && _GroupEdit->getMaxHistoric() && _GroupEdit->getCurrentHistoricIndex()>0)
438 // Get the start of the string.
439 ::u32string startStr= _GroupEdit->getInputStringRef().substr(0, _GroupEdit->getCursorPos());
441 // Search all historic string that match startStr.
442 for(sint i=_GroupEdit->getCurrentHistoricIndex()-1;i>=0;i--)
444 if( _GroupEdit->getHistoric(i).compare(0, _GroupEdit->getCursorPos(), startStr)==0 )
446 _GroupEdit->setInputStringRef (_GroupEdit->getHistoric(i));
447 _GroupEdit->setCurrentHistoricIndex(i);
448 break;
452 else if (_GroupEdit->getViewText()->getMultiLine())
454 float cx, cy;
455 float height;
456 _GroupEdit->getViewText()->getCharacterPositionFromIndex(_GroupEdit->getCursorPos() + (sint)_GroupEdit->getPromptRef().length(), _GroupEdit->isCursorAtPreviousLineEnd(), cx, cy, height);
457 if (cy != 0)
459 cy -= height;
460 uint newCharIndex;
461 bool newLineEnd;
462 _GroupEdit->getViewText()->getCharacterIndexFromPosition(cx, cy, newCharIndex, newLineEnd);
463 if (newLineEnd)
465 _GroupEdit->setCursorPos(newCharIndex - (sint32)_GroupEdit->getPromptRef().length());
466 _GroupEdit->setCursorAtPreviousLineEnd(true);
467 sint32 newPos = _GroupEdit->getCursorPos();
468 clamp(newPos, (sint32) 0, (sint32) _GroupEdit->getInputStringRef().size());
469 _GroupEdit->setCursorPos(newPos);
470 return;
472 _GroupEdit->setCursorAtPreviousLineEnd(false);
473 // takes character whose X is closer to the current X
474 float cx0, cx1;
475 float cy0, cy1;
476 _GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex, _GroupEdit->isCursorAtPreviousLineEnd(), cx0, cy0, height);
477 _GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex + 1, _GroupEdit->isCursorAtPreviousLineEnd(), cx1, cy1, height);
478 if (abs(cx0 - cx) < abs(cx1 - cx) || cy0 != cy1)
480 _GroupEdit->setCursorPos(newCharIndex);
482 else
484 _GroupEdit->setCursorPos(min(sint32(newCharIndex + 1), sint32(_GroupEdit->getInputStringRef().length() + _GroupEdit->getPromptRef().length())));
486 _GroupEdit->setCursorPos(_GroupEdit->getCursorPos()-(sint32)_GroupEdit->getPromptRef().length());
487 sint32 newPos = _GroupEdit->getCursorPos();
488 clamp(newPos, (sint32) 0, (sint32) _GroupEdit->getInputStringRef().size());
489 _GroupEdit->setCursorPos(newPos);
494 REGISTER_ACTION_HANDLER (CAHEditNextLine, "edit_next_line");
496 // ***************************************************************************
498 class CAHEditDeleteChar : public CAHEdit
500 protected:
501 void initPart ()
503 init();
505 void actionPart ()
507 // if selection is activated and not same cursors pos, then cut the selection
508 if(CGroupEditBox::getCurrSelection() != NULL && _GroupEdit->getCursorPos() != CGroupEditBox::getSelectCursorPos())
510 if (CGroupEditBox::getCurrSelection() != _GroupEdit)
512 nlwarning("Selection can only be on focus");
514 _GroupEdit->cutSelection();
515 // Change Handler
516 if (!_GroupEdit->getAHOnChange().empty())
518 CInterfaceManager *pIM = CInterfaceManager::getInstance();
519 CAHManager::getInstance()->runActionHandler(_GroupEdit->getAHOnChange(), _GroupEdit, _GroupEdit->getParamsOnChange());
522 // else cut forwards
523 else if(_GroupEdit->getCursorPos() < (sint32) _GroupEdit->getInputStringRef().length())
525 ::u32string inputString = _GroupEdit->getInputStringRef();
526 ::u32string::iterator it = inputString.begin() + _GroupEdit->getCursorPos();
527 inputString.erase(it);
528 _GroupEdit->setInputStringRef (inputString);
529 if (!_GroupEdit->getAHOnChange().empty())
531 CInterfaceManager *pIM = CInterfaceManager::getInstance();
532 CAHManager::getInstance()->runActionHandler(_GroupEdit->getAHOnChange(), _GroupEdit, _GroupEdit->getParamsOnChange());
535 // must stop selection in all case
536 CGroupEditBox::setCurrSelection(NULL);
537 _GroupEdit->setCursorAtPreviousLineEnd(false);
540 REGISTER_ACTION_HANDLER (CAHEditDeleteChar, "edit_delete_char");
542 // ***************************************************************************
544 class CAHEditSelectAll : public CAHEdit
546 void initPart ()
548 init();
550 void actionPart ()
552 _GroupEdit->setSelectionAll();
555 REGISTER_ACTION_HANDLER (CAHEditSelectAll, "edit_select_all");
557 // ***************************************************************************
559 class CAHEditCopy : public CAHEdit
561 void initPart ()
563 init();
565 void actionPart ()
567 _GroupEdit->copy();
569 void forwardToEditor()
571 R2::getEditor().copy();
574 REGISTER_ACTION_HANDLER (CAHEditCopy, "edit_copy");
576 // ***************************************************************************
578 class CAHEditPaste : public CAHEdit
580 void initPart ()
582 init();
584 void actionPart ()
586 _GroupEdit->paste();
588 void forwardToEditor()
590 R2::getEditor().paste();
593 REGISTER_ACTION_HANDLER (CAHEditPaste, "edit_paste");
595 // ***************************************************************************
597 class CAHEditCut : public CAHEditDeleteChar
599 void initPart ()
601 init();
603 void actionPart ()
605 // if selection is activated and not same cursors pos, then cut the selection
606 if(CGroupEditBox::getCurrSelection() != NULL && _GroupEdit->getCursorPos() != CGroupEditBox::getSelectCursorPos())
608 // Copy selection
609 _GroupEdit->copy();
611 // Cut selection
612 CAHEditDeleteChar::actionPart();
616 REGISTER_ACTION_HANDLER (CAHEditCut, "edit_cut");
618 // ***************************************************************************
620 class CAHEditExpand : public CAHEdit
622 void initPart ()
624 init();
626 void actionPart ()
628 _GroupEdit->expand();
631 REGISTER_ACTION_HANDLER (CAHEditExpand, "edit_expand");
633 // ***************************************************************************
634 class CAHEditExpandOrCycleTell : public CAHEdit
636 void initPart ()
638 init();
640 void actionPart ()
642 // If the line starts with '/tell ', do not try to expand
643 if (!NLMISC::startsWith(_GroupEdit->getInputString(), "/tell "))
645 if (_GroupEdit->expand()) return;
647 CInterfaceManager *im = CInterfaceManager::getInstance();
648 if (!im->isInGame()) return;
649 // there was no / at the start of the line so try to cycle through the last people on which a tell was done
650 const string *lastTellPeople = ChatMngr.cycleLastTell();
651 if (!lastTellPeople) return;
652 // Get chat box from ist edit box
653 // If it isn't a user chat or the main chat, just display 'tell' with the name. Otherwise, change the target of the window
654 CChatWindow *cw = getChatWndMgr().getChatWindowFromCaller(_GroupEdit);
655 if (!cw) return;
656 CFilteredChat *fc = PeopleInterraction.getFilteredChatFromChatWindow(cw);
657 if (fc)
659 fc->Filter.setTargetPlayer(*lastTellPeople);
661 else
663 // it is not a filtered chat, display 'tell' (must be ingame)
664 _GroupEdit->setCommand("tell " + (*lastTellPeople) + ' ', false);
668 REGISTER_ACTION_HANDLER (CAHEditExpandOrCycleTell, "edit_expand_or_cycle_tell");
670 // ***************************************************************************
672 class CAHEditBack: public CAHEdit
674 void initPart ()
676 init();
678 void actionPart ()
680 _GroupEdit->back();
683 REGISTER_ACTION_HANDLER (CAHEditBack, "edit_back");
685 // ***************************************************************************
687 class CAHEditSelectPreviousChar : public CAHEditPreviousChar
689 void initPart ()
691 init();
692 handleSelection();
695 REGISTER_ACTION_HANDLER (CAHEditSelectPreviousChar, "edit_select_previous_char");
697 // ***************************************************************************
699 class CAHEditSelectNextChar : public CAHEditNextChar
701 void initPart ()
703 init();
704 handleSelection();
707 REGISTER_ACTION_HANDLER (CAHEditSelectNextChar, "edit_select_next_char");
709 // ***************************************************************************
711 class CAHEditSelectPreviousWord : public CAHEditPreviousWord
713 void initPart ()
715 init();
716 handleSelection();
719 REGISTER_ACTION_HANDLER (CAHEditSelectPreviousWord, "edit_select_previous_word");
721 // ***************************************************************************
723 class CAHEditSelectNextWord : public CAHEditNextWord
725 void initPart ()
727 init();
728 handleSelection();
731 REGISTER_ACTION_HANDLER (CAHEditSelectNextWord, "edit_select_next_word");
733 // ***************************************************************************
735 class CAHEditSelectToLineBegin : public CAHEditGotoLineBegin
737 void initPart ()
739 init();
740 handleSelection();
743 REGISTER_ACTION_HANDLER (CAHEditSelectToLineBegin, "edit_select_to_line_begin");
745 // ***************************************************************************
747 class CAHEditSelectToLineEnd : public CAHEditGotoLineEnd
749 void initPart ()
751 init();
752 handleSelection();
755 REGISTER_ACTION_HANDLER (CAHEditSelectToLineEnd, "edit_select_to_line_end");
757 // ***************************************************************************
759 class CAHEditSelectToBlockBegin : public CAHEditGotoBlockBegin
761 void initPart ()
763 init();
764 handleSelection();
767 REGISTER_ACTION_HANDLER (CAHEditSelectToBlockBegin, "edit_select_to_block_begin");
769 // ***************************************************************************
771 class CAHEditSelectToBlockEnd : public CAHEditGotoBlockEnd
773 void initPart ()
775 init();
776 handleSelection();
779 REGISTER_ACTION_HANDLER (CAHEditSelectToBlockEnd, "edit_select_to_block_end");
781 // ***************************************************************************