LibreOffice Module starmath (master) 1
cursor.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9#include <cursor.hxx>
10#include <visitors.hxx>
11#include <document.hxx>
12#include <view.hxx>
13#include <comphelper/string.hxx>
14#include <comphelper/lok.hxx>
15#include <editeng/editeng.hxx>
16#include <LibreOfficeKit/LibreOfficeKitEnums.h>
17#include <osl/diagnose.h>
18#include <sfx2/lokhelper.hxx>
19
20void SmCursor::Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor){
21 SmCaretPosGraphEntry* NewPos = nullptr;
22 switch(direction)
23 {
24 case MoveLeft:
25 if (mpPosition)
26 NewPos = mpPosition->Left;
27 OSL_ENSURE(NewPos, "NewPos shouldn't be NULL here!");
28 break;
29 case MoveRight:
30 if (mpPosition)
31 NewPos = mpPosition->Right;
32 OSL_ENSURE(NewPos, "NewPos shouldn't be NULL here!");
33 break;
34 case MoveUp:
35 //Implementation is practically identical to MoveDown, except for a single if statement
36 //so I've implemented them together and added a direction == MoveDown to the if statements.
37 case MoveDown:
38 if (mpPosition)
39 {
41 best_line, //Best approximated line found so far
42 curr_line; //Current line
43 tools::Long dbp_sq = 0; //Distance squared to best line
44 for(const auto &pEntry : *mpGraph)
45 {
46 //Reject it if it's the current position
47 if(pEntry->CaretPos == mpPosition->CaretPos) continue;
48 //Compute caret line
49 curr_line = SmCaretPos2LineVisitor(pDev, pEntry->CaretPos).GetResult();
50 //Reject anything above if we're moving down
51 if(curr_line.GetTop() <= from_line.GetTop() && direction == MoveDown) continue;
52 //Reject anything below if we're moving up
53 if(curr_line.GetTop() + curr_line.GetHeight() >= from_line.GetTop() + from_line.GetHeight()
54 && direction == MoveUp) continue;
55 //Compare if it to what we have, if we have anything yet
56 if(NewPos){
57 //Compute distance to current line squared, multiplied with a horizontal factor
58 tools::Long dp_sq = curr_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
59 curr_line.SquaredDistanceY(from_line);
60 //Discard current line if best line is closer
61 if(dbp_sq <= dp_sq) continue;
62 }
63 //Take current line as the best
64 best_line = curr_line;
65 NewPos = pEntry.get();
66 //Update distance to best line
67 dbp_sq = best_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
68 best_line.SquaredDistanceY(from_line);
69 }
70 }
71 break;
72 default:
73 assert(false);
74 }
75 if(NewPos){
76 mpPosition = NewPos;
77 if(bMoveAnchor)
78 mpAnchor = NewPos;
80 }
81}
82
83void SmCursor::MoveTo(OutputDevice* pDev, const Point& pos, bool bMoveAnchor)
84{
85 SmCaretPosGraphEntry* NewPos = nullptr;
86 tools::Long dp_sq = 0, //Distance to current line squared
87 dbp_sq = 1; //Distance to best line squared
88 for(const auto &pEntry : *mpGraph)
89 {
90 OSL_ENSURE(pEntry->CaretPos.IsValid(), "The caret position graph may not have invalid positions!");
91 //Compute current line
92 SmCaretLine curr_line = SmCaretPos2LineVisitor(pDev, pEntry->CaretPos).GetResult();
93 //Compute squared distance to current line
94 dp_sq = curr_line.SquaredDistanceX(pos) + curr_line.SquaredDistanceY(pos);
95 //If we have a position compare to it
96 if(NewPos){
97 //If best line is closer, reject current line
98 if(dbp_sq <= dp_sq) continue;
99 }
100 //Accept current position as the best
101 NewPos = pEntry.get();
102 //Update distance to best line
103 dbp_sq = dp_sq;
104 }
105 if(NewPos){
106 mpPosition = NewPos;
107 if(bMoveAnchor)
108 mpAnchor = NewPos;
110 }
111}
112
114 //Save the current anchor and position
115 SmCaretPos _anchor, _position;
116 //Release mpGraph if allocated
117 if(mpGraph){
118 if(mpAnchor)
119 _anchor = mpAnchor->CaretPos;
120 if(mpPosition)
121 _position = mpPosition->CaretPos;
122 mpGraph.reset();
123 //Reset anchor and position as they point into an old graph
124 mpAnchor = nullptr;
125 mpPosition = nullptr;
126 }
127
128 //Build the new graph
130
131 //Restore anchor and position pointers
132 if(_anchor.IsValid() || _position.IsValid()){
133 for(const auto &pEntry : *mpGraph)
134 {
135 if(_anchor == pEntry->CaretPos)
136 mpAnchor = pEntry.get();
137 if(_position == pEntry->CaretPos)
138 mpPosition = pEntry.get();
139 }
140 }
141 //Set position and anchor to first caret position
142 auto it = mpGraph->begin();
143 assert(it != mpGraph->end());
144 if(!mpPosition)
145 mpPosition = it->get();
146 if(!mpAnchor)
148
149 assert(mpPosition);
150 assert(mpAnchor);
151 OSL_ENSURE(mpPosition->CaretPos.IsValid(), "Position must be valid");
152 OSL_ENSURE(mpAnchor->CaretPos.IsValid(), "Anchor must be valid");
153}
154
156 for(const auto &pEntry : *mpGraph)
157 {
158 if(pEntry->CaretPos == pos)
159 {
160 mpPosition = pEntry.get();
161 mpAnchor = pEntry.get();
162 return true;
163 }
164 }
165 return false;
166}
167
169 //TODO: Manage a state, reset it upon modification and optimize this call
171}
172
173void SmCursor::Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible){
174 SmCaretDrawingVisitor(pDev, GetPosition(), Offset, isCaretVisible);
175}
176
178{
179 return SmCaretRectanglesVisitor(rOutDev, GetPosition()).getCaret();
180}
181
183{
186}
187
189 //Delete only a selection if there's a selection
190 if(HasSelection()){
191 Delete();
192 return;
193 }
194
196 SmStructureNode* pLineParent = pLine->GetParent();
197 int nLineOffsetIdx = pLineParent->IndexOfSubNode(pLine);
198 assert(nLineOffsetIdx >= 0);
199
200 //If we're in front of a node who's parent is a TABLE
201 if (pLineParent->GetType() == SmNodeType::Table && mpPosition->CaretPos.nIndex == 0 && nLineOffsetIdx > 0)
202 {
203 size_t nLineOffset = nLineOffsetIdx;
204 //Now we can merge with nLineOffset - 1
205 BeginEdit();
206 //Line to merge things into, so we can delete pLine
207 SmNode* pMergeLine = pLineParent->GetSubNode(nLineOffset-1);
208 OSL_ENSURE(pMergeLine, "pMergeLine cannot be NULL!");
209 SmCaretPos PosAfterDelete;
210 //Convert first line to list
211 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
212 NodeToList(pMergeLine, *pLineList);
213 if(!pLineList->empty()){
214 //Find iterator to patch
215 SmNodeList::iterator patchPoint = pLineList->end();
216 --patchPoint;
217 //Convert second line to list
218 NodeToList(pLine, *pLineList);
219 //Patch the line list
220 ++patchPoint;
221 PosAfterDelete = PatchLineList(pLineList.get(), patchPoint);
222 //Parse the line
223 pLine = SmNodeListParser().Parse(pLineList.get());
224 }
225 pLineList.reset();
226 pLineParent->SetSubNode(nLineOffset-1, pLine);
227 //Delete the removed line slot
228 SmNodeArray lines(pLineParent->GetNumSubNodes()-1);
229 for (size_t i = 0; i < pLineParent->GetNumSubNodes(); ++i)
230 {
231 if(i < nLineOffset)
232 lines[i] = pLineParent->GetSubNode(i);
233 else if(i > nLineOffset)
234 lines[i-1] = pLineParent->GetSubNode(i);
235 }
236 pLineParent->SetSubNodes(std::move(lines));
237 //Rebuild graph
238 mpAnchor = nullptr;
239 mpPosition = nullptr;
240 BuildGraph();
242 //Set caret position
243 if(!SetCaretPosition(PosAfterDelete))
244 SetCaretPosition(SmCaretPos(pLine, 0));
245 //Finish editing
246 EndEdit();
247
248 //TODO: If we're in an empty (sub/super/*) script
249 /*}else if(pLineParent->GetType() == SmNodeType::SubSup &&
250 nLineOffset != 0 &&
251 pLine->GetType() == SmNodeType::Expression &&
252 pLine->GetNumSubNodes() == 0){
253 //There's a (sub/super) script we can delete
254 //Consider selecting the entire script if GetNumSubNodes() != 0 or pLine->GetType() != SmNodeType::Expression
255 //TODO: Handle case where we delete a limit
256 */
257
258 //Else move select, and delete if not complex
259 }else{
260 Move(pDev, MoveLeft, false);
262 Delete();
263 }
264}
265
267 //Return if we don't have a selection to delete
268 if(!HasSelection())
269 return;
270
271 //Enter edit section
272 BeginEdit();
273
274 //Set selected on nodes
276
277 //Find an arbitrary selected node
278 SmNode* pSNode = FindSelectedNode(mpTree);
279 assert(pSNode);
280
281 //Find the topmost node of the line that holds the selection
282 SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
283 OSL_ENSURE(pLine != mpTree, "Shouldn't be able to select the entire tree");
284
285 //Get the parent of the line
286 SmStructureNode* pLineParent = pLine->GetParent();
287 //Find line offset in parent
288 int nLineOffset = pLineParent->IndexOfSubNode(pLine);
289 assert(nLineOffset >= 0);
290
291 //Position after delete
292 SmCaretPos PosAfterDelete;
293
294 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
295 NodeToList(pLine, *pLineList);
296
297 //Take the selected nodes and delete them...
298 SmNodeList::iterator patchIt = TakeSelectedNodesFromList(pLineList.get());
299
300 //Get the position to set after delete
301 PosAfterDelete = PatchLineList(pLineList.get(), patchIt);
302
303 //Finish editing
304 FinishEdit(std::move(pLineList), pLineParent, nLineOffset, PosAfterDelete);
305}
306
307void SmCursor::InsertNodes(std::unique_ptr<SmNodeList> pNewNodes){
308 if(pNewNodes->empty()){
309 return;
310 }
311
312 //Begin edit section
313 BeginEdit();
314
315 //Get the current position
317
318 //Find top most of line that holds position
319 SmNode* pLine = FindTopMostNodeInLine(pos.pSelectedNode);
320 const bool bSelectedIsTopMost = pLine == pos.pSelectedNode;
321
322 //Find line parent and line index in parent
323 SmStructureNode* pLineParent = pLine->GetParent();
324 int nParentIndex = pLineParent->IndexOfSubNode(pLine);
325 assert(nParentIndex >= 0);
326
327 //Convert line to list
328 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
329 NodeToList(pLine, *pLineList); // deletes pLine, potentially deleting pos.pSelectedNode
330
331 //Find iterator for place to insert nodes
332 SmNodeList::iterator it = bSelectedIsTopMost ? pLineList->begin()
333 : FindPositionInLineList(pLineList.get(), pos);
334
335 //Insert all new nodes
336 SmNodeList::iterator newIt,
337 patchIt = it, // (pointless default value, fixes compiler warnings)
338 insIt;
339 for(newIt = pNewNodes->begin(); newIt != pNewNodes->end(); ++newIt){
340 insIt = pLineList->insert(it, *newIt);
341 if(newIt == pNewNodes->begin())
342 patchIt = insIt;
343 }
344 //Patch the places we've changed stuff
345 PatchLineList(pLineList.get(), patchIt);
346 SmCaretPos PosAfterInsert = PatchLineList(pLineList.get(), it);
347 //Release list, we've taken the nodes
348 pNewNodes.reset();
349
350 //Finish editing
351 FinishEdit(std::move(pLineList), pLineParent, nParentIndex, PosAfterInsert);
352}
353
354SmNodeList::iterator SmCursor::FindPositionInLineList(SmNodeList* pLineList,
355 const SmCaretPos& rCaretPos)
356{
357 //Find iterator for position
358 SmNodeList::iterator it = std::find(pLineList->begin(), pLineList->end(), rCaretPos.pSelectedNode);
359 if (it != pLineList->end())
360 {
361 if((*it)->GetType() == SmNodeType::Text)
362 {
363 //Split textnode if needed
364 if(rCaretPos.nIndex > 0)
365 {
366 SmTextNode* pText = static_cast<SmTextNode*>(rCaretPos.pSelectedNode);
367 if (rCaretPos.nIndex == pText->GetText().getLength())
368 return ++it;
369 OUString str1 = pText->GetText().copy(0, rCaretPos.nIndex);
370 OUString str2 = pText->GetText().copy(rCaretPos.nIndex);
371 pText->ChangeText(str1);
372 ++it;
373 //Insert str2 as new text node
374 assert(!str2.isEmpty());
375 SmTextNode* pNewText = new SmTextNode(pText->GetToken(), pText->GetFontDesc());
376 pNewText->ChangeText(str2);
377 it = pLineList->insert(it, pNewText);
378 }
379 }else
380 ++it;
381 //it now pointer to the node following pos, so pLineList->insert(it, ...) will insert correctly
382 return it;
383 }
384 //If we didn't find pSelectedNode, it must be because the caret is in front of the line
385 return pLineList->begin();
386}
387
388SmCaretPos SmCursor::PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter) {
389 //The nodes we should consider merging
390 SmNode *prev = nullptr,
391 *next = nullptr;
392 if(aIter != pLineList->end())
393 next = *aIter;
394 if(aIter != pLineList->begin()) {
395 --aIter;
396 prev = *aIter;
397 ++aIter;
398 }
399
400 //Check if there's textnodes to merge
401 if( prev &&
402 next &&
403 prev->GetType() == SmNodeType::Text &&
404 next->GetType() == SmNodeType::Text &&
405 ( prev->GetToken().eType != TNUMBER ||
406 next->GetToken().eType == TNUMBER) ){
407 SmTextNode *pText = static_cast<SmTextNode*>(prev),
408 *pOldN = static_cast<SmTextNode*>(next);
409 SmCaretPos retval(pText, pText->GetText().getLength());
410 OUString newText = pText->GetText() + pOldN->GetText();
411 pText->ChangeText(newText);
412 delete pOldN;
413 pLineList->erase(aIter);
414 return retval;
415 }
416
417 //Check if there's a SmPlaceNode to remove:
418 if(prev && next && prev->GetType() == SmNodeType::Place && !SmNodeListParser::IsOperator(next->GetToken())){
419 --aIter;
420 aIter = pLineList->erase(aIter);
421 delete prev;
422 //Return caret pos in front of aIter
423 if(aIter != pLineList->begin())
424 --aIter; //Thus find node before aIter
425 if(aIter == pLineList->begin())
426 return SmCaretPos();
427 return SmCaretPos::GetPosAfter(*aIter);
428 }
429 if(prev && next && next->GetType() == SmNodeType::Place && !SmNodeListParser::IsOperator(prev->GetToken())){
430 aIter = pLineList->erase(aIter);
431 delete next;
432 return SmCaretPos::GetPosAfter(prev);
433 }
434
435 //If we didn't do anything return
436 if(!prev) //return an invalid to indicate we're in front of line
437 return SmCaretPos();
438 return SmCaretPos::GetPosAfter(prev);
439}
440
441SmNodeList::iterator SmCursor::TakeSelectedNodesFromList(SmNodeList *pLineList,
442 SmNodeList *pSelectedNodes) {
443 SmNodeList::iterator retval;
444 SmNodeList::iterator it = pLineList->begin();
445 while(it != pLineList->end()){
446 if((*it)->IsSelected()){
447 //Split text nodes
448 if((*it)->GetType() == SmNodeType::Text) {
449 SmTextNode* pText = static_cast<SmTextNode*>(*it);
450 OUString aText = pText->GetText();
451 //Start and lengths of the segments, 2 is the selected segment
452 int start2 = pText->GetSelectionStart(),
453 start3 = pText->GetSelectionEnd(),
454 len1 = start2 - 0,
455 len2 = start3 - start2,
456 len3 = aText.getLength() - start3;
457 SmToken aToken = pText->GetToken();
458 sal_uInt16 eFontDesc = pText->GetFontDesc();
459 //If we need make segment 1
460 if(len1 > 0) {
461 OUString str = aText.copy(0, len1);
462 pText->ChangeText(str);
463 ++it;
464 } else {//Remove it if not needed
465 it = pLineList->erase(it);
466 delete pText;
467 }
468 //Set retval to be right after the selection
469 retval = it;
470 //if we need make segment 3
471 if(len3 > 0) {
472 OUString str = aText.copy(start3, len3);
473 SmTextNode* pSeg3 = new SmTextNode(aToken, eFontDesc);
474 pSeg3->ChangeText(str);
475 retval = pLineList->insert(it, pSeg3);
476 }
477 //If we need to save the selected text
478 if(pSelectedNodes && len2 > 0) {
479 OUString str = aText.copy(start2, len2);
480 SmTextNode* pSeg2 = new SmTextNode(aToken, eFontDesc);
481 pSeg2->ChangeText(str);
482 pSelectedNodes->push_back(pSeg2);
483 }
484 } else { //if it's not textnode
485 SmNode* pNode = *it;
486 retval = it = pLineList->erase(it);
487 if(pSelectedNodes)
488 pSelectedNodes->push_back(pNode);
489 else
490 delete pNode;
491 }
492 } else
493 ++it;
494 }
495 return retval;
496}
497
500
501 //Find line
502 SmNode *pLine;
503 if(HasSelection()) {
504 SmNode *pSNode = FindSelectedNode(mpTree);
505 assert(pSNode);
506 pLine = FindTopMostNodeInLine(pSNode, true);
507 } else
509
510 //Find Parent and offset in parent
511 SmStructureNode *pLineParent = pLine->GetParent();
512 int nParentIndex = pLineParent->IndexOfSubNode(pLine);
513 assert(nParentIndex >= 0);
514
515 //TODO: Consider handling special cases where parent is an SmOperNode,
516 // Maybe this method should be able to add limits to an SmOperNode...
517
518 //We begin modifying the tree here
519 BeginEdit();
520
521 //Convert line to list
522 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
523 NodeToList(pLine, *pLineList);
524
525 //Take the selection, and/or find iterator for current position
526 std::unique_ptr<SmNodeList> pSelectedNodesList(new SmNodeList);
527 SmNodeList::iterator it;
528 if(HasSelection())
529 it = TakeSelectedNodesFromList(pLineList.get(), pSelectedNodesList.get());
530 else
531 it = FindPositionInLineList(pLineList.get(), mpPosition->CaretPos);
532
533 //Find node that this should be applied to
534 SmNode* pSubject;
535 bool bPatchLine = !pSelectedNodesList->empty(); //If the line should be patched later
536 if(it != pLineList->begin()) {
537 --it;
538 pSubject = *it;
539 ++it;
540 } else {
541 //Create a new place node
542 pSubject = new SmPlaceNode();
543 pSubject->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
544 it = pLineList->insert(it, pSubject);
545 ++it;
546 bPatchLine = true; //We've modified the line it should be patched later.
547 }
548
549 //Wrap the subject in a SmSubSupNode
550 SmSubSupNode* pSubSup;
551 if(pSubject->GetType() != SmNodeType::SubSup){
552 SmToken token;
553 token.nGroup = TG::Power;
554 pSubSup = new SmSubSupNode(token);
555 pSubSup->SetBody(pSubject);
556 *(--it) = pSubSup;
557 ++it;
558 }else
559 pSubSup = static_cast<SmSubSupNode*>(pSubject);
560 //pSubject shouldn't be referenced anymore, pSubSup is the SmSubSupNode in pLineList we wish to edit.
561 //and it pointer to the element following pSubSup in pLineList.
562 pSubject = nullptr;
563
564 //Patch the line if we noted that was needed previously
565 if(bPatchLine)
566 PatchLineList(pLineList.get(), it);
567
568 //Convert existing, if any, sub-/superscript line to list
569 SmNode *pScriptLine = pSubSup->GetSubSup(eSubSup);
570 std::unique_ptr<SmNodeList> pScriptLineList(new SmNodeList);
571 NodeToList(pScriptLine, *pScriptLineList);
572
573 //Add selection to pScriptLineList
574 unsigned int nOldSize = pScriptLineList->size();
575 pScriptLineList->insert(pScriptLineList->end(), pSelectedNodesList->begin(), pSelectedNodesList->end());
576 pSelectedNodesList.reset();
577
578 //Patch pScriptLineList if needed
579 if(0 < nOldSize && nOldSize < pScriptLineList->size()) {
580 SmNodeList::iterator iPatchPoint = pScriptLineList->begin();
581 std::advance(iPatchPoint, nOldSize);
582 PatchLineList(pScriptLineList.get(), iPatchPoint);
583 }
584
585 //Find caret pos, that should be used after sub-/superscription.
586 SmCaretPos PosAfterScript; //Leave invalid for first position
587 if (!pScriptLineList->empty())
588 PosAfterScript = SmCaretPos::GetPosAfter(pScriptLineList->back());
589
590 //Parse pScriptLineList
591 pScriptLine = SmNodeListParser().Parse(pScriptLineList.get());
592 pScriptLineList.reset();
593
594 //Insert pScriptLine back into the tree
595 pSubSup->SetSubSup(eSubSup, pScriptLine);
596
597 //Finish editing
598 FinishEdit(std::move(pLineList), pLineParent, nParentIndex, PosAfterScript, pScriptLine);
599}
600
602 BeginEdit();
603
605
606 //Find line
607 SmNode *pLine;
608 if(HasSelection()) {
609 SmNode *pSNode = FindSelectedNode(mpTree);
610 assert(pSNode);
611 pLine = FindTopMostNodeInLine(pSNode, true);
612 } else
614
615 //Find parent and offset in parent
616 SmStructureNode *pLineParent = pLine->GetParent();
617 int nParentIndex = pLineParent->IndexOfSubNode(pLine);
618 assert(nParentIndex >= 0);
619
620 //Convert line to list
621 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
622 NodeToList(pLine, *pLineList);
623
624 //Take the selection, and/or find iterator for current position
625 std::unique_ptr<SmNodeList> pSelectedNodesList(new SmNodeList);
626 SmNodeList::iterator it;
627 if(HasSelection())
628 it = TakeSelectedNodesFromList(pLineList.get(), pSelectedNodesList.get());
629 else
630 it = FindPositionInLineList(pLineList.get(), mpPosition->CaretPos);
631
632 //If there's no selected nodes, create a place node
633 std::unique_ptr<SmNode> pBodyNode;
634 SmCaretPos PosAfterInsert;
635 if(pSelectedNodesList->empty()) {
636 pBodyNode.reset(new SmPlaceNode());
637 PosAfterInsert = SmCaretPos(pBodyNode.get(), 1);
638 } else
639 pBodyNode.reset(SmNodeListParser().Parse(pSelectedNodesList.get()));
640
641 pSelectedNodesList.reset();
642
643 //Create SmBraceNode
644 SmToken aTok(TLEFT, '\0', "left", TG::NONE, 5);
645 SmBraceNode *pBrace = new SmBraceNode(aTok);
647 std::unique_ptr<SmNode> pLeft( CreateBracket(eBracketType, true) ),
648 pRight( CreateBracket(eBracketType, false) );
649 std::unique_ptr<SmBracebodyNode> pBody(new SmBracebodyNode(SmToken()));
650 pBody->SetSubNodes(std::move(pBodyNode), nullptr);
651 pBrace->SetSubNodes(std::move(pLeft), std::move(pBody), std::move(pRight));
652 pBrace->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
653
654 //Insert into line
655 pLineList->insert(it, pBrace);
656 //Patch line (I think this is good enough)
657 SmCaretPos aAfter = PatchLineList(pLineList.get(), it);
658 if( !PosAfterInsert.IsValid() )
659 PosAfterInsert = aAfter;
660
661 //Finish editing
662 FinishEdit(std::move(pLineList), pLineParent, nParentIndex, PosAfterInsert);
663}
664
665SmNode *SmCursor::CreateBracket(SmBracketType eBracketType, bool bIsLeft) {
666 SmToken aTok;
667 if(bIsLeft){
668 switch(eBracketType){
670 aTok = SmToken(TLPARENT, MS_LPARENT, "(", TG::LBrace, 5);
671 break;
673 aTok = SmToken(TLBRACKET, MS_LBRACKET, "[", TG::LBrace, 5);
674 break;
676 aTok = SmToken(TLBRACE, MS_LBRACE, "lbrace", TG::LBrace, 5);
677 break;
678 }
679 } else {
680 switch(eBracketType) {
682 aTok = SmToken(TRPARENT, MS_RPARENT, ")", TG::RBrace, 5);
683 break;
685 aTok = SmToken(TRBRACKET, MS_RBRACKET, "]", TG::RBrace, 5);
686 break;
688 aTok = SmToken(TRBRACE, MS_RBRACE, "rbrace", TG::RBrace, 5);
689 break;
690 }
691 }
692 SmNode* pRetVal = new SmMathSymbolNode(aTok);
694 return pRetVal;
695}
696
699
700 //Find line
701 SmNode *pLine;
702 if(HasSelection()) {
703 SmNode *pSNode = FindSelectedNode(mpTree);
704 assert(pSNode);
705 pLine = FindTopMostNodeInLine(pSNode, true);
706 } else
708
709 //Find parent and offset in parent
710 SmStructureNode *pLineParent = pLine->GetParent();
711 int nParentIndex = pLineParent->IndexOfSubNode(pLine);
712 assert(nParentIndex >= 0);
713
714 //Discover the context of this command
715 SmTableNode *pTable = nullptr;
716 SmMatrixNode *pMatrix = nullptr;
717 int nTableIndex = nParentIndex;
718 if(pLineParent->GetType() == SmNodeType::Table)
719 pTable = static_cast<SmTableNode*>(pLineParent);
720 //If it's wrapped in a SmLineNode, we can still insert a newline
721 else if(pLineParent->GetType() == SmNodeType::Line &&
722 pLineParent->GetParent() &&
723 pLineParent->GetParent()->GetType() == SmNodeType::Table) {
724 //NOTE: This hack might give problems if we stop ignoring SmAlignNode
725 pTable = static_cast<SmTableNode*>(pLineParent->GetParent());
726 nTableIndex = pTable->IndexOfSubNode(pLineParent);
727 assert(nTableIndex >= 0);
728 }
729 if(pLineParent->GetType() == SmNodeType::Matrix)
730 pMatrix = static_cast<SmMatrixNode*>(pLineParent);
731
732 //If we're not in a context that supports InsertRow, return sal_False
733 if(!pTable && !pMatrix)
734 return false;
735
736 //Now we start editing
737 BeginEdit();
738
739 //Convert line to list
740 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
741 NodeToList(pLine, *pLineList);
742
743 //Find position in line
744 SmNodeList::iterator it;
745 if(HasSelection()) {
746 //Take the selected nodes and delete them...
747 it = TakeSelectedNodesFromList(pLineList.get());
748 } else
749 it = FindPositionInLineList(pLineList.get(), mpPosition->CaretPos);
750
751 //New caret position after inserting the newline/row in whatever context
752 SmCaretPos PosAfterInsert;
753
754 //If we're in the context of a table
755 if(pTable) {
756 std::unique_ptr<SmNodeList> pNewLineList(new SmNodeList);
757 //Move elements from pLineList to pNewLineList
758 SmNodeList& rLineList = *pLineList;
759 pNewLineList->splice(pNewLineList->begin(), rLineList, it, rLineList.end());
760 //Make sure it is valid again
761 it = pLineList->end();
762 if(it != pLineList->begin())
763 --it;
764 if(pNewLineList->empty())
765 pNewLineList->push_front(new SmPlaceNode());
766 //Parse new line
767 std::unique_ptr<SmNode> pNewLine(SmNodeListParser().Parse(pNewLineList.get()));
768 pNewLineList.reset();
769 //Wrap pNewLine in SmLineNode if needed
770 if(pLineParent->GetType() == SmNodeType::Line) {
771 std::unique_ptr<SmLineNode> pNewLineNode(new SmLineNode(SmToken(TNEWLINE, '\0', "newline")));
772 pNewLineNode->SetSubNodes(std::move(pNewLine), nullptr);
773 pNewLine = std::move(pNewLineNode);
774 }
775 //Get position
776 PosAfterInsert = SmCaretPos(pNewLine.get(), 0);
777 //Move other nodes if needed
778 for( int i = pTable->GetNumSubNodes(); i > nTableIndex + 1; i--)
779 pTable->SetSubNode(i, pTable->GetSubNode(i-1));
780
781 //Insert new line
782 pTable->SetSubNode(nTableIndex + 1, pNewLine.release());
783
784 //Check if we need to change token type:
785 if(pTable->GetNumSubNodes() > 2 && pTable->GetToken().eType == TBINOM) {
786 SmToken tok = pTable->GetToken();
787 tok.eType = TSTACK;
788 pTable->SetToken(tok);
789 }
790 }
791 //If we're in the context of a matrix
792 else {
793 //Find position after insert and patch the list
794 PosAfterInsert = PatchLineList(pLineList.get(), it);
795 //Move other children
796 sal_uInt16 rows = pMatrix->GetNumRows();
797 sal_uInt16 cols = pMatrix->GetNumCols();
798 int nRowStart = (nParentIndex - nParentIndex % cols) + cols;
799 for( int i = pMatrix->GetNumSubNodes() + cols - 1; i >= nRowStart + cols; i--)
800 pMatrix->SetSubNode(i, pMatrix->GetSubNode(i - cols));
801 for( int i = nRowStart; i < nRowStart + cols; i++) {
802 SmPlaceNode *pNewLine = new SmPlaceNode();
803 if(i == nParentIndex + cols)
804 PosAfterInsert = SmCaretPos(pNewLine, 0);
805 pMatrix->SetSubNode(i, pNewLine);
806 }
807 pMatrix->SetRowCol(rows + 1, cols);
808 }
809
810 //Finish editing
811 FinishEdit(std::move(pLineList), pLineParent, nParentIndex, PosAfterInsert);
812 //FinishEdit is actually used to handle situations where parent is an instance of
813 //SmSubSupNode. In this case parent should always be a table or matrix, however, for
814 //code reuse we just use FinishEdit() here too.
815 return true;
816}
817
820
821 //Find line
822 SmNode *pLine;
823 if(HasSelection()) {
824 SmNode *pSNode = FindSelectedNode(mpTree);
825 assert(pSNode);
826 pLine = FindTopMostNodeInLine(pSNode, true);
827 } else
829
830 //Find Parent and offset in parent
831 SmStructureNode *pLineParent = pLine->GetParent();
832 int nParentIndex = pLineParent->IndexOfSubNode(pLine);
833 assert(nParentIndex >= 0);
834
835 //We begin modifying the tree here
836 BeginEdit();
837
838 //Convert line to list
839 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
840 NodeToList(pLine, *pLineList);
841
842 //Take the selection, and/or find iterator for current position
843 std::unique_ptr<SmNodeList> pSelectedNodesList(new SmNodeList);
844 SmNodeList::iterator it;
845 if(HasSelection())
846 it = TakeSelectedNodesFromList(pLineList.get(), pSelectedNodesList.get());
847 else
848 it = FindPositionInLineList(pLineList.get(), mpPosition->CaretPos);
849
850 //Create pNum, and pDenom
851 bool bEmptyFraction = pSelectedNodesList->empty();
852 std::unique_ptr<SmNode> pNum( bEmptyFraction
853 ? new SmPlaceNode()
854 : SmNodeListParser().Parse(pSelectedNodesList.get()) );
855 std::unique_ptr<SmNode> pDenom(new SmPlaceNode());
856 pSelectedNodesList.reset();
857
858 //Create new fraction
859 SmBinVerNode *pFrac = new SmBinVerNode(SmToken(TOVER, '\0', "over", TG::Product, 0));
860 std::unique_ptr<SmNode> pRect(new SmRectangleNode(SmToken()));
861 pFrac->SetSubNodes(std::move(pNum), std::move(pRect), std::move(pDenom));
862
863 //Insert in pLineList
864 SmNodeList::iterator patchIt = pLineList->insert(it, pFrac);
865 PatchLineList(pLineList.get(), patchIt);
866 PatchLineList(pLineList.get(), it);
867
868 //Finish editing
869 SmNode *pSelectedNode = bEmptyFraction ? pFrac->GetSubNode(0) : pFrac->GetSubNode(2);
870 FinishEdit(std::move(pLineList), pLineParent, nParentIndex, SmCaretPos(pSelectedNode, 1));
871}
872
873void SmCursor::InsertText(const OUString& aString)
874{
875 BeginEdit();
876
877 Delete();
878
879 SmToken token;
880 token.eType = TIDENT;
881 token.cMathChar = u"";
882 token.nGroup = TG::NONE;
883 token.nLevel = 5;
884 token.aText = aString;
885
886 SmTextNode* pText = new SmTextNode(token, FNT_VARIABLE);
887 pText->SetText(aString);
888 pText->AdjustFontDesc();
889 pText->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
890
891 std::unique_ptr<SmNodeList> pList(new SmNodeList);
892 pList->push_front(pText);
893 InsertNodes(std::move(pList));
894
895 EndEdit();
896}
897
899 BeginEdit();
900
901 Delete();
902
903 //Create new node
904 SmNode* pNewNode = nullptr;
905 switch(element){
906 case BlankElement:
907 {
908 SmToken token;
909 token.eType = TBLANK;
910 token.nGroup = TG::Blank;
911 token.aText = "~";
912 SmBlankNode* pBlankNode = new SmBlankNode(token);
913 pBlankNode->IncreaseBy(token);
914 pNewNode = pBlankNode;
915 }break;
916 case FactorialElement:
917 {
918 SmToken token(TFACT, MS_FACT, "fact", TG::UnOper, 5);
919 pNewNode = new SmMathSymbolNode(token);
920 }break;
921 case PlusElement:
922 {
923 SmToken token;
924 token.eType = TPLUS;
925 token.setChar(MS_PLUS);
926 token.nGroup = TG::UnOper | TG::Sum;
927 token.nLevel = 5;
928 token.aText = "+";
929 pNewNode = new SmMathSymbolNode(token);
930 }break;
931 case MinusElement:
932 {
933 SmToken token;
934 token.eType = TMINUS;
935 token.setChar(MS_MINUS);
936 token.nGroup = TG::UnOper | TG::Sum;
937 token.nLevel = 5;
938 token.aText = "-";
939 pNewNode = new SmMathSymbolNode(token);
940 }break;
941 case CDotElement:
942 {
943 SmToken token;
944 token.eType = TCDOT;
945 token.setChar(MS_CDOT);
946 token.nGroup = TG::Product;
947 token.aText = "cdot";
948 pNewNode = new SmMathSymbolNode(token);
949 }break;
950 case EqualElement:
951 {
952 SmToken token;
953 token.eType = TASSIGN;
954 token.setChar(MS_ASSIGN);
955 token.nGroup = TG::Relation;
956 token.aText = "=";
957 pNewNode = new SmMathSymbolNode(token);
958 }break;
959 case LessThanElement:
960 {
961 SmToken token;
962 token.eType = TLT;
963 token.setChar(MS_LT);
964 token.nGroup = TG::Relation;
965 token.aText = "<";
966 pNewNode = new SmMathSymbolNode(token);
967 }break;
969 {
970 SmToken token;
971 token.eType = TGT;
972 token.setChar(MS_GT);
973 token.nGroup = TG::Relation;
974 token.aText = ">";
975 pNewNode = new SmMathSymbolNode(token);
976 }break;
977 case PercentElement:
978 {
979 SmToken token;
980 token.eType = TTEXT;
981 token.setChar(MS_PERCENT);
982 token.nGroup = TG::NONE;
983 token.aText = "\"%\"";
984 pNewNode = new SmMathSymbolNode(token);
985 }break;
986 }
987 assert(pNewNode);
988
989 //Prepare the new node
990 pNewNode->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
991
992 //Insert new node
993 std::unique_ptr<SmNodeList> pList(new SmNodeList);
994 pList->push_front(pNewNode);
995 InsertNodes(std::move(pList));
996
997 EndEdit();
998}
999
1000void SmCursor::InsertSpecial(std::u16string_view _aString)
1001{
1002 BeginEdit();
1003 Delete();
1004
1005 OUString aString( comphelper::string::strip(_aString, ' ') );
1006
1007 //Create instance of special node
1008 SmToken token;
1009 token.eType = TSPECIAL;
1010 token.cMathChar = u"";
1011 token.nGroup = TG::NONE;
1012 token.nLevel = 5;
1013 token.aText = aString;
1014 SmSpecialNode* pSpecial = new SmSpecialNode(token);
1015
1016 //Prepare the special node
1017 pSpecial->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
1018
1019 //Insert the node
1020 std::unique_ptr<SmNodeList> pList(new SmNodeList);
1021 pList->push_front(pSpecial);
1022 InsertNodes(std::move(pList));
1023
1024 EndEdit();
1025}
1026
1027void SmCursor::InsertCommandText(const OUString& aCommandText) {
1028 //Parse the sub expression
1029 auto xSubExpr = mpDocShell->GetParser()->ParseExpression(aCommandText);
1030
1031 //Prepare the subtree
1032 xSubExpr->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
1033
1034 //Convert subtree to list
1035 SmNode* pSubExpr = xSubExpr.release();
1036 std::unique_ptr<SmNodeList> pLineList(new SmNodeList);
1037 NodeToList(pSubExpr, *pLineList);
1038
1039 BeginEdit();
1040
1041 //Delete any selection
1042 Delete();
1043
1044 //Insert it
1045 InsertNodes(std::move(pLineList));
1046
1047 EndEdit();
1048}
1049
1051 if(!HasSelection())
1052 return;
1053
1055 //Find selected node
1056 SmNode* pSNode = FindSelectedNode(mpTree);
1057 assert(pSNode);
1058 //Find visual line
1059 SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
1060 assert(pLine);
1061
1062 //Clone selected nodes
1063 SmClipboard aClipboard;
1064 if(IsLineCompositionNode(pLine))
1065 CloneLineToClipboard(static_cast<SmStructureNode*>(pLine), &aClipboard);
1066 else{
1067 //Special care to only clone selected text
1068 if(pLine->GetType() == SmNodeType::Text) {
1069 SmTextNode *pText = static_cast<SmTextNode*>(pLine);
1070 std::unique_ptr<SmTextNode> pClone(new SmTextNode( pText->GetToken(), pText->GetFontDesc() ));
1071 int start = pText->GetSelectionStart(),
1072 length = pText->GetSelectionEnd() - pText->GetSelectionStart();
1073 pClone->ChangeText(pText->GetText().copy(start, length));
1074 pClone->SetScaleMode(pText->GetScaleMode());
1075 aClipboard.push_front(std::move(pClone));
1076 } else {
1077 SmCloningVisitor aCloneFactory;
1078 aClipboard.push_front(std::unique_ptr<SmNode>(aCloneFactory.Clone(pLine)));
1079 }
1080 }
1081
1082 //Set clipboard
1083 if (!aClipboard.empty())
1084 maClipboard = std::move(aClipboard);
1085}
1086
1088 BeginEdit();
1089 Delete();
1090
1091 if (!maClipboard.empty())
1093
1094 EndEdit();
1095}
1096
1097std::unique_ptr<SmNodeList> SmCursor::CloneList(SmClipboard &rClipboard){
1098 SmCloningVisitor aCloneFactory;
1099 std::unique_ptr<SmNodeList> pClones(new SmNodeList);
1100
1101 for(auto &xNode : rClipboard){
1102 SmNode *pClone = aCloneFactory.Clone(xNode.get());
1103 pClones->push_back(pClone);
1104 }
1105
1106 return pClones;
1107}
1108
1109SmNode* SmCursor::FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected){
1110 assert(pSNode);
1111 //Move up parent until we find a node who's
1112 //parent is NULL or isn't selected and not a type of:
1113 // SmExpressionNode
1114 // SmLineNode
1115 // SmBinHorNode
1116 // SmUnHorNode
1117 // SmAlignNode
1118 // SmFontNode
1119 while(pSNode->GetParent() &&
1120 ((MoveUpIfSelected &&
1121 pSNode->GetParent()->IsSelected()) ||
1122 IsLineCompositionNode(pSNode->GetParent())))
1123 pSNode = pSNode->GetParent();
1124 //Now we have the selection line node
1125 return pSNode;
1126}
1127
1129 if(pNode->GetNumSubNodes() == 0)
1130 return nullptr;
1131 for(auto pChild : *static_cast<SmStructureNode*>(pNode))
1132 {
1133 if(!pChild)
1134 continue;
1135 if(pChild->IsSelected())
1136 return pChild;
1137 SmNode* pRetVal = FindSelectedNode(pChild);
1138 if(pRetVal)
1139 return pRetVal;
1140 }
1141 return nullptr;
1142}
1143
1145 for(auto pChild : *pLine)
1146 {
1147 if (!pChild)
1148 continue;
1149 switch(pChild->GetType()){
1150 case SmNodeType::Line:
1151 case SmNodeType::UnHor:
1153 case SmNodeType::BinHor:
1154 case SmNodeType::Align:
1155 case SmNodeType::Font:
1156 LineToList(static_cast<SmStructureNode*>(pChild), list);
1157 break;
1158 case SmNodeType::Error:
1159 delete pChild;
1160 break;
1161 default:
1162 list.push_back(pChild);
1163 }
1164 }
1165 pLine->ClearSubNodes();
1166 delete pLine;
1167}
1168
1170 SmCloningVisitor aCloneFactory;
1171 for(auto pChild : *pLine)
1172 {
1173 if (!pChild)
1174 continue;
1175 if( IsLineCompositionNode( pChild ) )
1176 CloneLineToClipboard( static_cast<SmStructureNode*>(pChild), pClipboard );
1177 else if( pChild->IsSelected() && pChild->GetType() != SmNodeType::Error ) {
1178 //Only clone selected text from SmTextNode
1179 if(pChild->GetType() == SmNodeType::Text) {
1180 SmTextNode *pText = static_cast<SmTextNode*>(pChild);
1181 std::unique_ptr<SmTextNode> pClone(new SmTextNode( pChild->GetToken(), pText->GetFontDesc() ));
1182 int start = pText->GetSelectionStart(),
1183 length = pText->GetSelectionEnd() - pText->GetSelectionStart();
1184 pClone->ChangeText(pText->GetText().copy(start, length));
1185 pClone->SetScaleMode(pText->GetScaleMode());
1186 pClipboard->push_back(std::move(pClone));
1187 } else
1188 pClipboard->push_back(std::unique_ptr<SmNode>(aCloneFactory.Clone(pChild)));
1189 }
1190 }
1191}
1192
1194 switch(pNode->GetType()){
1195 case SmNodeType::Line:
1196 case SmNodeType::UnHor:
1198 case SmNodeType::BinHor:
1199 case SmNodeType::Align:
1200 case SmNodeType::Font:
1201 return true;
1202 default:
1203 return false;
1204 }
1205}
1206
1208 if(pNode->GetNumSubNodes() == 0)
1209 return 0;
1210 int nCount = 0;
1211 for(auto pChild : *static_cast<SmStructureNode*>(pNode))
1212 {
1213 if (!pChild)
1214 continue;
1215 if(pChild->IsSelected() && !IsLineCompositionNode(pChild))
1216 nCount++;
1217 nCount += CountSelectedNodes(pChild);
1218 }
1219 return nCount;
1220}
1221
1223 if(!HasSelection())
1224 return false;
1226
1227 return CountSelectedNodes(mpTree) > 1;
1228}
1229
1230void SmCursor::FinishEdit(std::unique_ptr<SmNodeList> pLineList,
1231 SmStructureNode* pParent,
1232 int nParentIndex,
1233 SmCaretPos PosAfterEdit,
1234 SmNode* pStartLine) {
1235 //Store number of nodes in line for later
1236 int entries = pLineList->size();
1237
1238 //Parse list of nodes to a tree
1240 std::unique_ptr<SmNode> pLine(parser.Parse(pLineList.get()));
1241 pLineList.reset();
1242
1243 //Check if we're making the body of a subsup node bigger than one
1244 if(pParent->GetType() == SmNodeType::SubSup &&
1245 nParentIndex == 0 &&
1246 entries > 1) {
1247 //Wrap pLine in scalable round brackets
1248 SmToken aTok(TLEFT, '\0', "left", TG::NONE, 5);
1249 std::unique_ptr<SmBraceNode> pBrace(new SmBraceNode(aTok));
1250 pBrace->SetScaleMode(SmScaleMode::Height);
1251 std::unique_ptr<SmNode> pLeft( CreateBracket(SmBracketType::Round, true) ),
1252 pRight( CreateBracket(SmBracketType::Round, false) );
1253 std::unique_ptr<SmBracebodyNode> pBody(new SmBracebodyNode(SmToken()));
1254 pBody->SetSubNodes(std::move(pLine), nullptr);
1255 pBrace->SetSubNodes(std::move(pLeft), std::move(pBody), std::move(pRight));
1256 pBrace->Prepare(mpDocShell->GetFormat(), *mpDocShell, 0);
1257 pLine = std::move(pBrace);
1258 //TODO: Consider the following alternative behavior:
1259 //Consider the line: A + {B + C}^D lsub E
1260 //Here pLineList is B, + and C and pParent is a subsup node with
1261 //both RSUP and LSUB set. Imagine the user just inserted "B +" in
1262 //the body of the subsup node...
1263 //The most natural thing to do would be to make the line like this:
1264 //A + B lsub E + C ^ D
1265 //E.g. apply LSUB and LSUP to the first element in pLineList and RSUP
1266 //and RSUB to the last element in pLineList. But how should this act
1267 //for CSUP and CSUB ???
1268 //For this reason and because brackets was faster to implement, this solution
1269 //have been chosen. It might be worth working on the other solution later...
1270 }
1271
1272 //Set pStartLine if NULL
1273 if(!pStartLine)
1274 pStartLine = pLine.get();
1275
1276 //Insert it back into the parent
1277 pParent->SetSubNode(nParentIndex, pLine.release());
1278
1279 //Rebuild graph of caret position
1280 mpAnchor = nullptr;
1281 mpPosition = nullptr;
1282 BuildGraph();
1283 AnnotateSelection(); //Update selection annotation!
1284
1285 //Set caret position
1286 if(!SetCaretPosition(PosAfterEdit))
1287 SetCaretPosition(SmCaretPos(pStartLine, 0));
1288
1289 //End edit section
1290 EndEdit();
1291}
1292
1294 if(mnEditSections++ > 0) return;
1295
1298 mpDocShell->EnableSetModified( false );
1299}
1300
1302 if(--mnEditSections > 0) return;
1303
1305 //Okay, I don't know what this does... :)
1306 //It's used in SmDocShell::SetText and with places where everything is modified.
1307 //I think it does some magic, with sfx, but everything is totally undocumented so
1308 //it's kinda hard to tell...
1311 //I think this notifies people around us that we've modified this document...
1313 //I think SmDocShell uses this value when it sends an update graphics event
1314 //Anyway comments elsewhere suggests it needs to be updated...
1316
1317 //TODO: Consider copying the update accessibility code from SmDocShell::SetText in here...
1318 //This somehow updates the size of SmGraphicView if it is running in embedded mode
1319 if( mpDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1321
1322 //Request a repaint...
1324
1325 //Update the edit engine and text of the document
1326 OUString formula;
1331}
1332
1334{
1335 if (SmViewShell *pViewSh = SmGetActiveView())
1336 {
1338 {
1339 pViewSh->SendCaretToLOK();
1340 }
1341 else if ( SfxObjectCreateMode::EMBEDDED == mpDocShell->GetCreateMode() )
1343 else
1344 pViewSh->GetGraphicWidget().Invalidate();
1345 }
1346}
1347
1349{
1350 const SmCaretPos pos = GetPosition();
1351 if (!pos.IsValid()) {
1352 return false;
1353 }
1354
1355 SmNode* pNode = pos.pSelectedNode;
1356
1357 if (pNode->GetType() == SmNodeType::Text) {
1358 SmTextNode* pTextNode = static_cast<SmTextNode*>(pNode);
1359 if (pos.nIndex < pTextNode->GetText().getLength()) {
1360 // The cursor is on a text node and at the middle of it.
1361 return false;
1362 }
1363 } else {
1364 if (pos.nIndex < 1) {
1365 return false;
1366 }
1367 }
1368
1369 while (true) {
1370 SmStructureNode* pParentNode = pNode->GetParent();
1371 if (!pParentNode) {
1372 // There's no brace body node in the ancestors.
1373 return false;
1374 }
1375
1376 int index = pParentNode->IndexOfSubNode(pNode);
1377 assert(index >= 0);
1378 if (static_cast<size_t>(index + 1) != pParentNode->GetNumSubNodes()) {
1379 // The cursor is not at the tail at one of ancestor nodes.
1380 return false;
1381 }
1382
1383 pNode = pParentNode;
1384 if (pNode->GetType() == SmNodeType::Bracebody) {
1385 // Found the brace body node.
1386 break;
1387 }
1388 }
1389
1390 SmStructureNode* pBraceNodeTmp = pNode->GetParent();
1391 if (!pBraceNodeTmp || pBraceNodeTmp->GetType() != SmNodeType::Brace) {
1392 // Brace node is invalid.
1393 return false;
1394 }
1395
1396 SmBraceNode* pBraceNode = static_cast<SmBraceNode*>(pBraceNodeTmp);
1397 SmMathSymbolNode* pClosingNode = pBraceNode->ClosingBrace();
1398 if (!pClosingNode) {
1399 // Couldn't get closing symbol node.
1400 return false;
1401 }
1402
1403 // Check if the closing brace matches eBracketType.
1404 SmTokenType eClosingTokenType = pClosingNode->GetToken().eType;
1405 switch (eBracketType) {
1406 case SmBracketType::Round: if (eClosingTokenType != TRPARENT) { return false; } break;
1407 case SmBracketType::Square: if (eClosingTokenType != TRBRACKET) { return false; } break;
1408 case SmBracketType::Curly: if (eClosingTokenType != TRBRACE) { return false; } break;
1409 default:
1410 return false;
1411 }
1412
1413 return true;
1414}
1415
1417
1419 pList = list;
1420 //Delete error nodes
1421 SmNodeList::iterator it = pList->begin();
1422 while(it != pList->end()) {
1423 if((*it)->GetType() == SmNodeType::Error){
1424 //Delete and erase
1425 delete *it;
1426 it = pList->erase(it);
1427 }else
1428 ++it;
1429 }
1430 SmNode* retval = Expression();
1431 pList = nullptr;
1432 return retval;
1433}
1434
1436 SmNodeArray NodeArray;
1437 //Accept as many relations as there is
1438 while(Terminal())
1439 NodeArray.push_back(Relation());
1440
1441 //Create SmExpressionNode, I hope SmToken() will do :)
1443 pExpr->SetSubNodes(std::move(NodeArray));
1444 return pExpr;
1445}
1446
1448 //Read a sum
1449 std::unique_ptr<SmNode> pLeft(Sum());
1450 //While we have tokens and the next is a relation
1451 while(Terminal() && IsRelationOperator(Terminal()->GetToken())){
1452 //Take the operator
1453 std::unique_ptr<SmNode> pOper(Take());
1454 //Find the right side of the relation
1455 std::unique_ptr<SmNode> pRight(Sum());
1456 //Create new SmBinHorNode
1457 std::unique_ptr<SmStructureNode> pNewNode(new SmBinHorNode(SmToken()));
1458 pNewNode->SetSubNodes(std::move(pLeft), std::move(pOper), std::move(pRight));
1459 pLeft = std::move(pNewNode);
1460 }
1461 return pLeft.release();
1462}
1463
1465 //Read a product
1466 std::unique_ptr<SmNode> pLeft(Product());
1467 //While we have tokens and the next is a sum
1468 while(Terminal() && IsSumOperator(Terminal()->GetToken())){
1469 //Take the operator
1470 std::unique_ptr<SmNode> pOper(Take());
1471 //Find the right side of the sum
1472 std::unique_ptr<SmNode> pRight(Product());
1473 //Create new SmBinHorNode
1474 std::unique_ptr<SmStructureNode> pNewNode(new SmBinHorNode(SmToken()));
1475 pNewNode->SetSubNodes(std::move(pLeft), std::move(pOper), std::move(pRight));
1476 pLeft = std::move(pNewNode);
1477 }
1478 return pLeft.release();
1479}
1480
1482 //Read a Factor
1483 std::unique_ptr<SmNode> pLeft(Factor());
1484 //While we have tokens and the next is a product
1485 while(Terminal() && IsProductOperator(Terminal()->GetToken())){
1486 //Take the operator
1487 std::unique_ptr<SmNode> pOper(Take());
1488 //Find the right side of the operation
1489 std::unique_ptr<SmNode> pRight(Factor());
1490 //Create new SmBinHorNode
1491 std::unique_ptr<SmStructureNode> pNewNode(new SmBinHorNode(SmToken()));
1492 pNewNode->SetSubNodes(std::move(pLeft), std::move(pOper), std::move(pRight));
1493 pLeft = std::move(pNewNode);
1494 }
1495 return pLeft.release();
1496}
1497
1499 //Read unary operations
1500 if(!Terminal())
1501 return Error();
1502 //Take care of unary operators
1503 else if(IsUnaryOperator(Terminal()->GetToken()))
1504 {
1505 SmStructureNode *pUnary = new SmUnHorNode(SmToken());
1506 std::unique_ptr<SmNode> pOper(Terminal()),
1507 pArg;
1508
1509 if(Next())
1510 pArg.reset(Factor());
1511 else
1512 pArg.reset(Error());
1513
1514 pUnary->SetSubNodes(std::move(pOper), std::move(pArg));
1515 return pUnary;
1516 }
1517 return Postfix();
1518}
1519
1521 if(!Terminal())
1522 return Error();
1523 std::unique_ptr<SmNode> pArg;
1524 if(IsPostfixOperator(Terminal()->GetToken()))
1525 pArg.reset(Error());
1526 else if(IsOperator(Terminal()->GetToken()))
1527 return Error();
1528 else
1529 pArg.reset(Take());
1530 while(Terminal() && IsPostfixOperator(Terminal()->GetToken())) {
1531 std::unique_ptr<SmStructureNode> pUnary(new SmUnHorNode(SmToken()) );
1532 std::unique_ptr<SmNode> pOper(Take());
1533 pUnary->SetSubNodes(std::move(pArg), std::move(pOper));
1534 pArg = std::move(pUnary);
1535 }
1536 return pArg.release();
1537}
1538
1540 return new SmErrorNode(SmToken());
1541}
1542
1544 return IsRelationOperator(token) ||
1545 IsSumOperator(token) ||
1546 IsProductOperator(token) ||
1547 IsUnaryOperator(token) ||
1548 IsPostfixOperator(token);
1549}
1550
1552 return bool(token.nGroup & TG::Relation);
1553}
1554
1556 return bool(token.nGroup & TG::Sum);
1557}
1558
1560 return token.nGroup & TG::Product &&
1561 token.eType != TWIDESLASH &&
1562 token.eType != TWIDEBACKSLASH &&
1563 token.eType != TUNDERBRACE &&
1564 token.eType != TOVERBRACE &&
1565 token.eType != TOVER;
1566}
1567
1569 return token.nGroup & TG::UnOper &&
1570 (token.eType == TPLUS ||
1571 token.eType == TMINUS ||
1572 token.eType == TPLUSMINUS ||
1573 token.eType == TMINUSPLUS ||
1574 token.eType == TNEG ||
1575 token.eType == TUOPER);
1576}
1577
1579 return token.eType == TFACT;
1580}
1581
1582/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual std::unique_ptr< SmNode > ParseExpression(const OUString &rBuffer)=0
Parse rBuffer to formula subtree that constitutes an expression.
void QuickFormatDoc(bool bFull=false)
void QuickInsertText(const OUString &rText, const ESelection &rSel)
bool IsEnableSetModified() const
void EnableSetModified(bool bEnable=true)
SfxObjectCreateMode GetCreateMode() const
Binary horizontal node.
Definition: node.hxx:1368
Binary horizontal node.
Definition: node.hxx:1425
Node for whitespace.
Definition: node.hxx:2056
void IncreaseBy(const SmToken &rToken, sal_uInt32 nMultiplyBy=1)
Definition: node.cxx:2314
Node for brace construction.
Definition: node.hxx:1646
const SmMathSymbolNode * ClosingBrace() const
Returns the node containing the data of the closing brace.
Definition: node.hxx:1674
Body of an SmBraceNode.
Definition: node.hxx:1710
Visitor for drawing a caret position.
Definition: visitors.hxx:161
A line that represents a caret.
Definition: caret.hxx:61
tools::Long SquaredDistanceY(const SmCaretLine &line) const
Definition: caret.hxx:80
tools::Long GetHeight() const
Definition: caret.hxx:71
tools::Long SquaredDistanceX(const SmCaretLine &line) const
Definition: caret.hxx:72
tools::Long GetTop() const
Definition: caret.hxx:69
Visitor getting a line from a caret position.
Definition: visitors.hxx:178
const SmCaretLine & GetResult() const
Definition: visitors.hxx:192
A visitor for building a SmCaretPosGraph.
Definition: visitors.hxx:335
const tools::Rectangle & getCaret() const
Definition: visitors.hxx:147
Visitor for cloning a pNode.
Definition: visitors.hxx:383
SmNode * Clone(SmNode *pNode)
Clone a pNode.
Definition: visitors.cxx:1513
void Delete()
Delete the current selection or do nothing.
Definition: cursor.cxx:266
void InsertElement(SmFormulaElement element)
Insert an element into the formula.
Definition: cursor.cxx:898
static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList, SmNodeList *pSelectedNodes=nullptr)
Take selected nodes from a list.
Definition: cursor.cxx:441
void InsertFraction()
Insert a fraction, use selection as numerator.
Definition: cursor.cxx:818
SmCaretPosGraphEntry * mpPosition
Definition: cursor.hxx:197
const SmCaretPos & GetPosition() const
Get position.
Definition: cursor.hxx:84
void InsertBrackets(SmBracketType eBracketType)
Create brackets around current selection, or new SmPlaceNode.
Definition: cursor.cxx:601
void Copy()
Copy the current selection.
Definition: cursor.cxx:1050
static SmNode * CreateBracket(SmBracketType eBracketType, bool bIsLeft)
Create an instance of SmMathSymbolNode usable for brackets.
Definition: cursor.cxx:665
void DeletePrev(OutputDevice *pDev)
Delete selection, previous element or merge lines.
Definition: cursor.cxx:188
void Draw(OutputDevice &pDev, Point Offset, bool isCaretVisible)
Draw the caret.
Definition: cursor.cxx:173
SmNode * mpTree
Formula tree.
Definition: cursor.hxx:199
static SmNode * FindTopMostNodeInLine(SmNode *pSNode, bool MoveUpIfSelected=false)
Finds the topmost node in a visual line.
Definition: cursor.cxx:1109
SmCaretPosGraphEntry * mpAnchor
Definition: cursor.hxx:197
bool HasSelection() const
True, if the cursor has a selection.
Definition: cursor.hxx:87
bool IsAtTailOfBracket(SmBracketType eBracketType) const
Definition: cursor.cxx:1348
static std::unique_ptr< SmNodeList > CloneList(SmClipboard &rClipboard)
Clone list of nodes in a clipboard (creates a deep clone)
Definition: cursor.cxx:1097
void InsertNodes(std::unique_ptr< SmNodeList > pNewNodes)
Insert new nodes in the tree after position.
Definition: cursor.cxx:307
int CountSelectedNodes(SmNode *pNode)
Count number of selected nodes, excluding line composition nodes.
Definition: cursor.cxx:1207
void FinishEdit(std::unique_ptr< SmNodeList > pLineList, SmStructureNode *pParent, int nParentIndex, SmCaretPos PosAfterEdit, SmNode *pStartLine=nullptr)
Finish editing.
Definition: cursor.cxx:1230
void EndEdit()
End edit section where the tree will be modified.
Definition: cursor.cxx:1301
void MoveTo(OutputDevice *pDev, const Point &pos, bool bMoveAnchor)
Move to the caret position closest to a given point.
Definition: cursor.cxx:83
static void NodeToList(SmNode *&rpNode, SmNodeList &rList)
Auxiliary function for calling LineToList on a node.
Definition: cursor.hxx:238
SmClipboard maClipboard
Clipboard holder.
Definition: cursor.hxx:205
void Paste()
Paste the clipboard.
Definition: cursor.cxx:1087
SmNode * FindSelectedNode(SmNode *pNode)
Returns a node that is selected, if any could be found.
Definition: cursor.cxx:1128
static void CloneLineToClipboard(SmStructureNode *pLine, SmClipboard *pClipboard)
Clone a visual line to a clipboard.
Definition: cursor.cxx:1169
void BuildGraph()
Build pGraph over caret positions.
Definition: cursor.cxx:113
SmDocShell * mpDocShell
Owner of the formula tree.
Definition: cursor.hxx:201
void RequestRepaint()
Request the formula is repainted.
Definition: cursor.cxx:1333
bool SetCaretPosition(SmCaretPos pos)
tries to set position to a specific SmCaretPos
Definition: cursor.cxx:155
int mnEditSections
The number of times BeginEdit have been called Used to allow nesting of BeginEdit() and EndEdit() sec...
Definition: cursor.hxx:330
bool HasComplexSelection()
Returns true if more than one node is selected.
Definition: cursor.cxx:1222
static bool IsLineCompositionNode(SmNode const *pNode)
Is this one of the nodes used to compose a line.
Definition: cursor.cxx:1193
std::unique_ptr< SmCaretPosGraph > mpGraph
Graph over caret position in the current tree.
Definition: cursor.hxx:203
tools::Rectangle GetCaretRectangle(OutputDevice &rOutDev) const
Definition: cursor.cxx:177
void InsertSubSup(SmSubSup eSubSup)
Create sub-/super script.
Definition: cursor.cxx:498
void InsertCommandText(const OUString &aCommandText)
Insert command text translated into line entries at position.
Definition: cursor.cxx:1027
static SmNodeList::iterator FindPositionInLineList(SmNodeList *pLineList, const SmCaretPos &rCaretPos)
Find an iterator pointing to the node in pLineList following rCaretPos.
Definition: cursor.cxx:354
bool InsertRow()
Insert a new row or newline.
Definition: cursor.cxx:697
void BeginEdit()
Begin edit section where the tree will be modified.
Definition: cursor.cxx:1293
bool mbIsEnabledSetModifiedSmDocShell
Holds data for BeginEdit() and EndEdit()
Definition: cursor.hxx:332
static void LineToList(SmStructureNode *pLine, SmNodeList &rList)
Convert a visual line to a list.
Definition: cursor.cxx:1144
static SmCaretPos PatchLineList(SmNodeList *pLineList, SmNodeList::iterator aIter)
Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
Definition: cursor.cxx:388
void AnnotateSelection() const
Set selected on nodes of the tree.
Definition: cursor.cxx:168
void InsertText(const OUString &aString)
Insert text at the current position.
Definition: cursor.cxx:873
void Move(OutputDevice *pDev, SmMovementDirection direction, bool bMoveAnchor=true)
Move the position of this cursor.
Definition: cursor.cxx:20
tools::Rectangle GetSelectionRectangle(OutputDevice &rOutDev) const
Definition: cursor.cxx:182
void InsertSpecial(std::u16string_view aString)
Insert a special node created from aString.
Definition: cursor.cxx:1000
virtual void OnDocumentPrinterChanged(Printer *) override
Definition: document.cxx:514
EditEngine & GetEditEngine()
Definition: document.cxx:287
void SetFormulaArranged(bool bVal)
Definition: document.hxx:124
void Repaint()
Definition: document.cxx:525
OUString maText
Definition: document.hxx:82
virtual void SetModified(bool bModified=true) override
Definition: document.cxx:1210
const SmFormat & GetFormat() const
Definition: document.hxx:172
AbstractSmParser * GetParser()
Definition: document.hxx:175
sal_uInt16 mnModifyCount
Definition: document.hxx:92
Error node, for parsing errors.
Definition: node.hxx:1097
Expression node.
Definition: node.hxx:1244
A line.
Definition: node.hxx:1178
Math symbol node.
Definition: node.hxx:955
Matrix node.
Definition: node.hxx:2000
void SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
Sets the dimensions of the matrix.
Definition: node.hxx:2028
sal_uInt16 GetNumRows() const
Gets the number of rows of the matrix.
Definition: node.hxx:2014
sal_uInt16 GetNumCols() const
Gets the number of columns of the matrix.
Definition: node.hxx:2020
Minimalistic recursive decent SmNodeList parser.
Definition: cursor.hxx:377
SmNode * Postfix()
Definition: cursor.cxx:1520
SmNode * Parse(SmNodeList *list)
Parse a list of nodes to an expression.
Definition: cursor.cxx:1418
SmNode * Product()
Definition: cursor.cxx:1481
SmNode * Expression()
Definition: cursor.cxx:1435
static bool IsOperator(const SmToken &token)
True, if the token is an operator.
Definition: cursor.cxx:1543
static bool IsRelationOperator(const SmToken &token)
True, if the token is a relation operator.
Definition: cursor.cxx:1551
SmNode * Sum()
Definition: cursor.cxx:1464
SmNode * Next()
Move to next terminal.
Definition: cursor.hxx:409
SmNode * Relation()
Definition: cursor.cxx:1447
static SmNode * Error()
Definition: cursor.cxx:1539
SmNode * Take()
Take the current terminal.
Definition: cursor.hxx:415
static bool IsProductOperator(const SmToken &token)
True, if the token is a product operator.
Definition: cursor.cxx:1559
static bool IsUnaryOperator(const SmToken &token)
True, if the token is a unary operator.
Definition: cursor.cxx:1568
SmNodeList * pList
Definition: cursor.hxx:400
static bool IsSumOperator(const SmToken &token)
True, if the token is a sum operator.
Definition: cursor.cxx:1555
static bool IsPostfixOperator(const SmToken &token)
True, if the token is a postfix operator.
Definition: cursor.cxx:1578
SmNode * Factor()
Definition: cursor.cxx:1498
SmNode * Terminal()
Get the current terminal.
Definition: cursor.hxx:402
Extract command text from pNodes.
Definition: visitors.hxx:465
Definition: node.hxx:125
SmScaleMode GetScaleMode() const
Gets the scale mode.
Definition: node.hxx:362
virtual size_t GetNumSubNodes() const =0
Gets the number of subnodes.
virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
Prepare preliminary settings about font and text (e.g.
Definition: node.cxx:207
const SmToken & GetToken() const
Gets the token.
Definition: node.hxx:387
bool IsSelected() const
Checks if the node is selected.
Definition: node.hxx:430
void SetScaleMode(SmScaleMode eMode)
Sets the scale mode to eMode.
Definition: node.hxx:369
const SmStructureNode * GetParent() const
Gets the parent node of this node.
Definition: node.hxx:443
SmNodeType GetType() const
Gets the node type.
Definition: node.hxx:379
void SetToken(SmToken const &token)
Sets the token for this node.
Definition: node.hxx:458
Place node.
Definition: node.hxx:1056
Draws a rectangle.
Definition: node.hxx:665
const tools::Rectangle & GetSelection()
Definition: visitors.hxx:437
Set Selection Visitor Sets the IsSelected( ) property on all SmNodes of the tree.
Definition: visitors.hxx:276
Special node for user defined characters.
Definition: node.hxx:878
virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override
Prepare preliminary settings about font and text (e.g.
Definition: node.cxx:2176
Abstract baseclass for all composite node.
Definition: node.hxx:471
int IndexOfSubNode(SmNode const *pSubNode)
Get the index of the child node pSubNode.
Definition: node.cxx:468
virtual size_t GetNumSubNodes() const override
Gets the number of subnodes.
Definition: node.cxx:430
void SetSubNodes(std::unique_ptr< SmNode > pFirst, std::unique_ptr< SmNode > pSecond, std::unique_ptr< SmNode > pThird=nullptr)
Sets subnodes, used for operators.
Definition: node.cxx:364
virtual SmNode * GetSubNode(size_t nIndex) override
Gets the subnode of index nIndex.
Definition: node.cxx:435
void SetSubNode(size_t nIndex, SmNode *pNode)
Sets the subnode pNode at nIndex.
Definition: node.cxx:477
void ClearSubNodes()
Does the cleaning of the subnodes.
Definition: node.cxx:359
Super- and subscript node.
Definition: node.hxx:1559
void SetSubSup(SmSubSup eSubSup, SmNode *pScript)
Sets the node with the data of what has to be superindex or subindex.
Definition: node.hxx:1611
const SmNode * GetSubSup(SmSubSup eSubSup) const
Gets the node with the data of what has to be superindex or subindex.
Definition: node.hxx:1595
void SetBody(SmNode *pBody)
Sets the node with the data of what has to be superindex or subindex.
Definition: node.hxx:1603
Table node.
Definition: node.hxx:1139
Text node.
Definition: node.hxx:747
void ChangeText(const OUString &rText)
Change the text of this node, including the underlying token to rText.
Definition: node.cxx:1836
void AdjustFontDesc()
Try to guess the correct FontDesc, used during visual editing.
Definition: node.cxx:1887
void SetText(const OUString &rText)
Sets the node text to rText.
Definition: node.hxx:776
const OUString & GetText() const
Gets the node text.
Definition: node.hxx:782
sal_Int32 GetSelectionStart() const
Index within GetText() where the selection starts.
Definition: node.hxx:803
sal_uInt16 GetFontDesc() const
Returns the font type being used (text, variable, symbol, ...).
Definition: node.hxx:769
sal_Int32 GetSelectionEnd() const
Index within GetText() where the selection ends.
Definition: node.hxx:810
virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override
Prepare preliminary settings about font and text (e.g.
Definition: node.cxx:1842
Unary horizontal node.
Definition: node.hxx:1272
SmFormulaElement
Enum of elements that can inserted into a formula.
Definition: cursor.hxx:32
@ FactorialElement
Definition: cursor.hxx:34
@ CDotElement
Definition: cursor.hxx:37
@ MinusElement
Definition: cursor.hxx:36
@ BlankElement
Definition: cursor.hxx:33
@ GreaterThanElement
Definition: cursor.hxx:40
@ EqualElement
Definition: cursor.hxx:38
@ PlusElement
Definition: cursor.hxx:35
@ LessThanElement
Definition: cursor.hxx:39
@ PercentElement
Definition: cursor.hxx:41
std::list< SmNode * > SmNodeList
A list of nodes.
Definition: cursor.hxx:56
#define HORIZONTICAL_DISTANCE_FACTOR
Factor to multiple the squared horizontal distance with Used for Up and Down movement.
Definition: cursor.hxx:19
std::list< std::unique_ptr< SmNode > > SmClipboard
Definition: cursor.hxx:58
SmBracketType
Bracket types that can be inserted.
Definition: cursor.hxx:46
@ Round
Round brackets, left command "(".
@ Square
Square brackets, left command "[".
@ Curly
Curly brackets, left command "lbrace".
SmMovementDirection
Enum of direction for movement.
Definition: cursor.hxx:23
@ MoveDown
Definition: cursor.hxx:25
@ MoveRight
Definition: cursor.hxx:27
@ MoveUp
Definition: cursor.hxx:24
@ MoveLeft
Definition: cursor.hxx:26
int nCount
float u
#define EE_PARA_ALL
#define EE_TEXTPOS_ALL
#define FNT_VARIABLE
Definition: format.hxx:46
size
OString strip(const OString &rIn, char c)
int i
index
parser
long Long
std::vector< SmNode * > SmNodeArray
Definition: node.hxx:113
SmSubSup
Enum used to index sub-/supscripts in the 'maSubNodes' array in 'SmSubSupNode'.
Definition: node.hxx:1536
An entry in SmCaretPosGraph.
Definition: caret.hxx:111
SmCaretPosGraphEntry * Left
Entry to the left visually.
Definition: caret.hxx:121
SmCaretPosGraphEntry * Right
Entry to the right visually.
Definition: caret.hxx:123
const SmCaretPos CaretPos
Caret position.
Definition: caret.hxx:119
Representation of caret position with an equation.
Definition: caret.hxx:17
bool IsValid() const
True, if this is a valid caret position.
Definition: caret.hxx:41
int nIndex
Index (invariant: non-negative) within the selected node.
Definition: caret.hxx:38
SmNode * pSelectedNode
Selected node.
Definition: caret.hxx:26
static SmCaretPos GetPosAfter(SmNode *pNode)
Get the caret position after pNode, regardless of pNode.
Definition: caret.hxx:51
SmTokenType eType
Definition: token.hxx:213
sal_uInt16 nLevel
Definition: token.hxx:218
OUString cMathChar
Definition: token.hxx:214
OUString aText
Definition: token.hxx:212
TG nGroup
Definition: token.hxx:217
void setChar(sal_Unicode cChar)
Definition: token.hxx:283
@ RBrace
@ LBrace
@ Relation
@ Sum
@ NONE
@ UnOper
@ Power
@ Product
@ Blank
SmTokenType
Definition: token.hxx:71
@ TLBRACKET
Definition: token.hxx:128
@ TSTACK
Definition: token.hxx:91
@ TBINOM
Definition: token.hxx:91
@ TGT
Definition: token.hxx:80
@ TLEFT
Definition: token.hxx:126
@ TMINUS
Definition: token.hxx:79
@ TOVER
Definition: token.hxx:87
@ TSPECIAL
Definition: token.hxx:74
@ TNUMBER
Definition: token.hxx:124
@ TUOPER
Definition: token.hxx:105
@ TRBRACKET
Definition: token.hxx:128
@ TRBRACE
Definition: token.hxx:130
@ TLBRACE
Definition: token.hxx:130
@ TASSIGN
Definition: token.hxx:81
@ TUNDERBRACE
Definition: token.hxx:126
@ TNEG
Definition: token.hxx:93
@ TWIDESLASH
Definition: token.hxx:88
@ TLT
Definition: token.hxx:80
@ TLPARENT
Definition: token.hxx:127
@ TFACT
Definition: token.hxx:144
@ TPLUS
Definition: token.hxx:79
@ TBLANK
Definition: token.hxx:75
@ TNEWLINE
Definition: token.hxx:76
@ TWIDEBACKSLASH
Definition: token.hxx:88
@ TPLUSMINUS
Definition: token.hxx:85
@ TTEXT
Definition: token.hxx:124
@ TIDENT
Definition: token.hxx:124
@ TOVERBRACE
Definition: token.hxx:126
@ TMINUSPLUS
Definition: token.hxx:85
@ TRPARENT
Definition: token.hxx:127
@ TCDOT
Definition: token.hxx:87
sal_Unicode const MS_FACT
Definition: types.hxx:41
sal_Unicode const MS_LBRACKET
Definition: types.hxx:167
sal_Unicode const MS_PLUS
Definition: types.hxx:56
sal_Unicode const MS_LT
Definition: types.hxx:72
sal_Unicode const MS_MINUS
Definition: types.hxx:57
sal_Unicode const MS_RBRACKET
Definition: types.hxx:168
sal_Unicode const MS_CDOT
Definition: types.hxx:60
sal_Unicode const MS_ASSIGN
Definition: types.hxx:52
sal_Unicode const MS_RPARENT
Definition: types.hxx:166
sal_Unicode const MS_PERCENT
Definition: types.hxx:197
sal_Unicode const MS_RBRACE
Definition: types.hxx:170
sal_Unicode const MS_GT
Definition: types.hxx:73
sal_Unicode const MS_LBRACE
Definition: types.hxx:169
sal_Unicode const MS_LPARENT
Definition: types.hxx:165
SmViewShell * SmGetActiveView()
! Since this method is based on the current focus it is somewhat ! unreliable and may return unexpect...
Definition: utility.cxx:33
size_t pos