Enable line deletion in starmath

* Implemented SmCursor::DeletePrev, for deletion of lines
* Fixed nasty bug in SmCursor::InsertRow
* Code cleanup in cursor.cxx
This commit is contained in:
Jonas Finnemann Jensen 2010-11-24 09:36:21 +01:00
parent aede297486
commit 592777e2b2
3 changed files with 115 additions and 70 deletions

View file

@ -132,6 +132,12 @@ public:
/** Delete the current selection or do nothing */
void Delete();
/** Delete selection, previous element or merge lines
*
* This method implements the behaviour of backspace.
*/
void DeletePrev(OutputDevice* pDev);
/** Insert text at the current position */
void InsertText(XubString aString);
@ -270,6 +276,28 @@ private:
*/
static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
/** Auxiliary function for calling LineToList on a node
*
* This method sets pNode = NULL and remove it from it's parent.
* (Assuming it has a parent, and is a child of it).
*/
static SmNodeList* NodeToList(SmNode*& rpNode, SmNodeList* pList = new SmNodeList()){
//Remove from parent and NULL rpNode
SmNode* pNode = rpNode;
if(rpNode && rpNode->GetParent()){ //Don't remove this, correctness relies on it
int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
if(index != -1)
rpNode->GetParent()->SetSubNode(index, NULL);
}
rpNode = NULL;
//Create line from node
if(pNode && IsLineCompositionNode(pNode))
return LineToList((SmStructureNode*)pNode, pList);
if(pNode)
pList->push_front(pNode);
return pList;
}
/** Clone a visual line to a list
*
* Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.

View file

@ -186,6 +186,76 @@ void SmCursor::Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible){
SmCaretDrawingVisitor(pDev, GetPosition(), Offset, isCaretVisible);
}
void SmCursor::DeletePrev(OutputDevice* pDev){
//Delete only a selection if there's a selection
if(HasSelection()){
Delete();
return;
}
SmNode* pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode);
SmStructureNode* pLineParent = pLine->GetParent();
int nLineOffset = pLineParent->IndexOfSubNode(pLine);
//If we're in front of a node who's parent is a TABLE
if(pLineParent->GetType() == NTABLE && position->CaretPos.Index == 0 && nLineOffset > 0){
//Now we can merge with nLineOffset - 1
BeginEdit();
//Line to merge things into, so we can delete pLine
SmNode* pMergeLine = pLineParent->GetSubNode(nLineOffset-1);
j_assert(pMergeLine, "pMergeLine cannot be NULL!");
//Convert first line to list
SmNodeList *pLineList = NodeToList(pMergeLine);
//Find iterator to patch
SmNodeList::iterator patchPoint = pLineList->end();
patchPoint--;
//Convert second line to list
NodeToList(pLine, pLineList);
//Patch the line list
patchPoint++;
SmCaretPos PosAfterDelete = PatchLineList(pLineList, patchPoint);
//Parse the line
pLine = SmNodeListParser().Parse(pLineList);
delete pLineList;
pLineParent->SetSubNode(nLineOffset-1, pLine);
//Delete the removed line slot
SmNodeArray lines(pLineParent->GetNumSubNodes()-1);
for(int i = 0; i < pLineParent->GetNumSubNodes(); i++){
if(i < nLineOffset)
lines[i] = pLineParent->GetSubNode(i);
else if(i > nLineOffset)
lines[i-1] = pLineParent->GetSubNode(i);
}
pLineParent->SetSubNodes(lines);
//Rebuild graph
anchor = NULL;
position = NULL;
BuildGraph();
AnnotateSelection();
//Set caret position
if(!SetCaretPosition(PosAfterDelete, true))
SetCaretPosition(SmCaretPos(pLine, 0), true);
//Finish editing
EndEdit();
//TODO: If we're in an empty (sub/super/*) script
/*}else if(pLineParent->GetType() == NSUBSUP &&
nLineOffset != 0 &&
pLine->GetType() == NEXPRESSION &&
pLine->GetNumSubNodes() == 0){
//There's a (sub/super/*) script we can delete
//Consider selecting the entire script if GetNumSubNodes() != 0 or pLine->GetType() != NEXPRESSION
//TODO: Handle case where we delete a limit
*/
//Else move select, and delete if not complex
}else{
this->Move(pDev, MoveLeft, false);
if(!this->HasComplexSelection())
Delete();
}
}
void SmCursor::Delete(){
//Return if we don't have a selection to delete
if(!HasSelection())
@ -214,13 +284,7 @@ void SmCursor::Delete(){
//Position after delete
SmCaretPos PosAfterDelete;
SmNodeList* pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_back(pLine);
}
SmNodeList* pLineList = NodeToList(pLine);
//Take the selected nodes and delete them...
SmNodeList::iterator patchIt = TakeSelectedNodesFromList(pLineList);
@ -256,13 +320,7 @@ void SmCursor::InsertNodes(SmNodeList* pNewNodes){
j_assert(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
//Convert line to list
SmNodeList* pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList* pLineList = NodeToList(pLine);
//Find iterator for place to insert nodes
SmNodeList::iterator it = FindPositionInLineList(pLineList, pos);
@ -465,13 +523,7 @@ void SmCursor::InsertSubSup(SmSubSup eSubSup) {
BeginEdit();
//Convert line to list
SmNodeList* pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList* pLineList = NodeToList(pLine);
//Take the selection, and/or find iterator for current position
SmNodeList* pSelectedNodesList = new SmNodeList();
@ -518,14 +570,7 @@ void SmCursor::InsertSubSup(SmSubSup eSubSup) {
//Convert existing, if any, sub-/superscript line to list
SmNode *pScriptLine = pSubSup->GetSubSup(eSubSup);
SmNodeList* pScriptLineList;
if(pScriptLine && IsLineCompositionNode(pScriptLine))
pScriptLineList = LineToList((SmStructureNode*)pScriptLine);
else{
pScriptLineList = new SmNodeList();
if(pScriptLine)
pScriptLineList->push_front(pScriptLine);
}
SmNodeList* pScriptLineList = NodeToList(pScriptLine);
//Add selection to pScriptLineList
unsigned int nOldSize = pScriptLineList->size();
@ -601,13 +646,7 @@ bool SmCursor::InsertLimit(SmSubSup eSubSup, bool bMoveCaret) {
//If it's already there... let's move the caret
} else if(bMoveCaret){
pLine = pSubSup->GetSubSup(eSubSup);
SmNodeList* pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList* pLineList = NodeToList(pLine);
if(pLineList->size() > 0)
PosAfterLimit = SmCaretPos::GetPosAfter(pLineList->back());
pLine = SmNodeListParser().Parse(pLineList);
@ -649,13 +688,7 @@ void SmCursor::InsertBrackets(SmBracketType eBracketType) {
j_assert( nParentIndex != -1, "pLine must be a subnode of pLineParent!");
//Convert line to list
SmNodeList *pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList *pLineList = NodeToList(pLine);
//Take the selection, and/or find iterator for current position
SmNodeList *pSelectedNodesList = new SmNodeList();
@ -816,13 +849,7 @@ bool SmCursor::InsertRow() {
BeginEdit();
//Convert line to list
SmNodeList *pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList *pLineList = NodeToList(pLine);
//Find position in line
SmNodeList::iterator it;
@ -849,20 +876,21 @@ bool SmCursor::InsertRow() {
//Parse new line
SmNode *pNewLine = SmNodeListParser().Parse(pNewLineList);
delete pNewLineList;
//Get position before we wrap in SmLineNode
//NOTE: This should be done after, if SmLineNode ever becomes a line composition node
PosAfterInsert = SmCaretPos(pNewLine, 0);
//Wrap pNewLine in SmLineNode if needed
if(pLineParent->GetType() == NLINE) {
SmLineNode *pNewLineNode = new SmLineNode(SmToken(TNEWLINE, '\0', "newline"));
pNewLineNode->SetSubNodes(pNewLine, NULL);
pNewLine = pNewLineNode;
}
//Get position
PosAfterInsert = SmCaretPos(pNewLine, 0);
//Move other nodes if needed
for( int i = pTable->GetNumSubNodes(); i > nTableIndex + 1; i--)
pTable->SetSubNode(i, pTable->GetSubNode(i-1));
//Insert new line
pTable->SetSubNode(nTableIndex + 1, pNewLine);
//Check if we need to change token type:
if(pTable->GetNumSubNodes() > 2 && pTable->GetToken().eType == TBINOM) {
SmToken tok = pTable->GetToken();
@ -919,13 +947,7 @@ void SmCursor::InsertFraction() {
BeginEdit();
//Convert line to list
SmNodeList* pLineList;
if(IsLineCompositionNode(pLine))
pLineList = LineToList((SmStructureNode*)pLine);
else {
pLineList = new SmNodeList();
pLineList->push_front(pLine);
}
SmNodeList* pLineList = NodeToList(pLine);
//Take the selection, and/or find iterator for current position
SmNodeList* pSelectedNodesList = new SmNodeList();
@ -957,7 +979,6 @@ void SmCursor::InsertFraction() {
FinishEdit(pLineList, pLineParent, nParentIndex, SmCaretPos(pDenom, 1));
}
void SmCursor::InsertText(XubString aString){
BeginEdit();
@ -1142,13 +1163,7 @@ void SmCursor::InsertCommandText(XubString aCommandText) {
pSubExpr->Prepare(pDocShell->GetFormat(), *pDocShell);
//Convert subtree to list
SmNodeList* pLineList;
if(IsLineCompositionNode(pSubExpr))
pLineList = LineToList((SmStructureNode*)pSubExpr);
else {
pLineList = new SmNodeList();
pLineList->push_front(pSubExpr);
}
SmNodeList* pLineList = NodeToList(pSubExpr);
BeginEdit();
@ -1219,7 +1234,6 @@ SmNodeList* SmCursor::CloneList(SmNodeList* pList){
return pClones;
}
void SmCursor::SetClipboard(SmNodeList* pList){
if(pClipboard){
//Delete all nodes on the clipboard

View file

@ -451,7 +451,6 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
#endif /* DEBUG_ENABLE_DUMPASDOT */
}break;
case KEY_DELETE:
case KEY_BACKSPACE:
{
if(!rCursor.HasSelection()){
rCursor.Move(this, nCode == KEY_DELETE ? MoveRight : MoveLeft, false);
@ -459,6 +458,10 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
}
rCursor.Delete();
}break;
case KEY_BACKSPACE:
{
rCursor.DeletePrev(this);
}break;
case KEY_ADD:
rCursor.InsertElement(PlusElement);
break;