/** * Yudit Unicode Editor Source File * * GNU Copyright (C) 1997-2006 Gaspar Sinai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, * dated June 1991. See file COPYYING for details. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include /** * All editors are like this one. */ SEditor::SEditor(void) { cleared = false; paragBreak = "\n"; editorIF = 0; vimode = false; undoIndex = 0; setup(); } SEditor::SEditor (const SString& lb) { cleared = false; paragBreak = lb; editorIF = 0; vimode = false; undoIndex = 0; setup(); } void SEditor::setup() { inputMethods.append (SS_DEFAULT_IM); inputMethods.append ("unicode"); inputMethods.append (SS_KINPUT2_IM); inputMethods.append ("Hungarian"); inputMethods.append ("Kana"); inputMethods.append ("Hangul"); fonts.append (SS_DEFAULT_FONT); fonts.append ("Bitmap"); fonts.append ("TrueType"); } /** * Copy editor and lose undo's */ SEditor::SEditor (const SEditor& in) { editorIF = in.editorIF; vimode = in.vimode; inputMethods = in.inputMethods; fonts = in.fonts; undoIndex = 0; paragBreak = in.paragBreak; } /** * Copy editor and lose undo's */ SEditor SEditor::operator=(const SEditor& in) { editorIF = in.editorIF; vimode = in.vimode; inputMethods = in.inputMethods; fonts = in.fonts; undoIndex = 0; paragBreak = in.paragBreak; return *this; } SEditor::~SEditor () { } void SEditor::setInterface(SEditorIF* _editorIF) { editorIF = _editorIF; } /** * called when a key has been pressed. */ void SEditor::keyPressed (SWindowListener::SKey key, const SString& s, bool ctrl, bool shift, bool meta) { if (editorIF == 0) return; if (key == SWindowListener::Key_Shift_R || key==SWindowListener::Key_Meta_L || key==SWindowListener::Key_Meta_R || key==SWindowListener::Key_Control_R || key==SWindowListener::Key_Control_L || key==SWindowListener::Key_Shift_L) { return; } /* Whoops - we did not receive keyrelease */ //Enable selection with SHIFT, // Addition by Maarten van Gompel if (editorIF->isSelecting() && !meta && !shift && !ctrl ) { editorIF->endSelect(); } SString erasedString ; SCursorIndex b = editorIF->getCursorIndex(); SCursorIndex a; SCursorIndex ba; SUndo::SType std; SS_Embedding embd = editorIF->getDocumentEmbedding(); cleared = false; SString lineBreak = paragBreak; if (ctrl||meta) lineBreak = SS_LB_LS; /* If there's a selection, erase it first before adding new input*/ if ((key != SWindowListener::Key_F1) && (key != SWindowListener::Key_F2) && (key != SWindowListener::Key_F3) && (key != SWindowListener::Key_F4) && (key != SWindowListener::Key_F5) && (key != SWindowListener::Key_F6) && (key != SWindowListener::Key_F7) && (key != SWindowListener::Key_F8) && (key != SWindowListener::Key_F9) && (key != SWindowListener::Key_F10) && (key != SWindowListener::Key_F11) && (key != SWindowListener::Key_F12) && (key != SWindowListener::Key_Control_R) && (key != SWindowListener::Key_Control_L) && (key != SWindowListener::Key_Meta_R) && (key != SWindowListener::Key_Meta_L) && (key != SWindowListener::Key_Alt_R) && (key != SWindowListener::Key_Alt_L) && (key != SWindowListener::Key_Left) && (key != SWindowListener::Key_Right) && (key != SWindowListener::Key_Up) && (key != SWindowListener::Key_Down) && (key != SWindowListener::Key_Prior) && (key != SWindowListener::Key_Next) && (key != SWindowListener::Key_Home) && (key != SWindowListener::Key_End) && (key != SWindowListener::Key_Escape) && (!ctrl) && (!meta)) { std = SUndo::SS_EraseSelect; STextIndex mba = editorIF->getSelectedIndex(true); ba = SCursorIndex (mba.line, mba.index); erasedString = editorIF->eraseSelectedText(); if (erasedString.size() != 0) { a = editorIF->getCursorIndex(); add (SUndo(std, editorIF->getDirection (), embd, erasedString, b, a, ba)); } } switch (key) { case SWindowListener::Key_Escape: // vi if (vimode) { editorIF->setEditable(!editorIF->isEditable()); } else { editorIF->focusOut(); } return; case SWindowListener::Key_Home: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } if (ctrl || meta) { editorIF->setCursorIndex(SCursorIndex(0,0)); if (editorIF->isSelecting()) { if (meta) { editorIF->selectText (editorIF->getCursorIndex()); } else // ctrl should just go to end without selecting. { editorIF->deselectText(); } } } else { SCursorIndex ti = editorIF->getCursorIndex(); ti.textIndex.index = 0; ti.before = true; editorIF->setCursorIndex(ti); if (editorIF->isSelecting()) { editorIF->selectText (editorIF->getCursorIndex()); } } break; case SWindowListener::Key_End: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } if (ctrl || meta) { editorIF->setCursorIndex(SCursorIndex(100000000,100000000)); if (editorIF->isSelecting()) { if (meta) { editorIF->selectText (editorIF->getCursorIndex()); } else // ctrl should just go to end without selecting. { editorIF->deselectText(); } } } else { SCursorIndex ti = editorIF->getCursorIndex(); ti.textIndex.index = 100000000; ti.before =true; editorIF->setCursorIndex(ti); if (editorIF->isSelecting()) { editorIF->selectText (editorIF->getCursorIndex()); } } break; case SWindowListener::Key_Prior: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->pageUp(); return; case SWindowListener::Key_Next: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->pageDown(); return; case SWindowListener::Key_Up: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->caretUp(); return; case SWindowListener::Key_Down: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->caretDown(); return; case SWindowListener::Key_Left: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->caretLeft(); return; case SWindowListener::Key_Right: if ((shift || ctrl || meta) && !editorIF->isSelecting()) { editorIF->startSelect(); } editorIF->caretRight(); return; /*SGC*/ case SWindowListener::Key_BackSpace: /* switch - delete a single character */ if (erasedString.size() == 0) { std = SUndo::SS_BackSpaceOne; erasedString = editorIF->backspace(); /* not even used */ ba = editorIF->getCursorIndex(); add (SUndo(std, editorIF->getDirection (), embd, erasedString, b, ba, ba)); } return; case SWindowListener::Key_Delete: /* switch - backspace */ if (erasedString.size() == 0) { std = SUndo::SS_EraseOne; erasedString = editorIF->erase(); /* not even used */ ba = editorIF->getCursorIndex(); add (SUndo(std, editorIF->getDirection (), embd, erasedString, b, ba, ba)); } return; case SWindowListener::Key_Enter: editorIF->insertDirtyText(lineBreak); ba = editorIF->getCursorIndex(); if (cleared) return; a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Insert, editorIF->getDirection (), embd, lineBreak, b, a, ba)); break; case SWindowListener::Key_Return: editorIF->insertDirtyText(lineBreak); ba = editorIF->getCursorIndex(); if (cleared) return; a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Insert, editorIF->getDirection (), embd, lineBreak, b, a, ba)); break; case SWindowListener::Key_F1: fKey (0, ctrl|shift|meta); break; case SWindowListener::Key_F2: fKey (1, ctrl|shift|meta); break; case SWindowListener::Key_F3: fKey (2, ctrl|shift|meta); break; case SWindowListener::Key_F4: fKey (3, ctrl|shift|meta); break; case SWindowListener::Key_F5: fKey (4, ctrl|shift|meta); break; case SWindowListener::Key_F6: fKey (5, ctrl|shift|meta); break; case SWindowListener::Key_F7: fKey (6, ctrl|shift|meta); break; case SWindowListener::Key_F8: fKey (7, ctrl|shift|meta); break; case SWindowListener::Key_F9: fKey (8, ctrl|shift|meta); break; case SWindowListener::Key_F10: fKey (9, ctrl|shift|meta); break; case SWindowListener::Key_F11: fKey (10, ctrl|shift|meta); break; case SWindowListener::Key_F12: fKey (11, ctrl|shift|meta); break; case SWindowListener::Key_B: case SWindowListener::Key_b: if (ctrl|meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->pageUp (); break; } case SWindowListener::Key_c: if (ctrl|meta) { if (editorIF->isSelecting()) editorIF->endSelect(); return; /* Automatic copy */ } /* This is used with accelerator anyway - this is never called here */ case SWindowListener::Key_Y: case SWindowListener::Key_y: if (ctrl|meta) { editorIF->setDirection (SS_DR_L); break; } case SWindowListener::Key_D: case SWindowListener::Key_d: if (ctrl|meta) { if (editorIF->getDirection () != SS_DR_RO) { editorIF->setDirection (SS_DR_RO); } else { editorIF->setDirection (SS_DR_LO); } break; } /* This is used with accelerator anyway - this is never called here */ case SWindowListener::Key_E: case SWindowListener::Key_e: if (ctrl|meta) { if (editorIF->getDirection () != SS_DR_RE) { editorIF->setDirection (SS_DR_RE); } else { editorIF->setDirection (SS_DR_LE); } break; } case SWindowListener::Key_F: case SWindowListener::Key_f: if (ctrl|meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->pageDown (); break; } case SWindowListener::Key_H: case SWindowListener::Key_h: if (ctrl|meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->caretLeft (); break; } case SWindowListener::Key_J: case SWindowListener::Key_j: case SWindowListener::Key_N: case SWindowListener::Key_n: if (ctrl||meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->caretDown (); break; } case SWindowListener::Key_K: case SWindowListener::Key_k: if (ctrl|meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->caretUp (); break; } case SWindowListener::Key_L: case SWindowListener::Key_l: if (ctrl||meta) { if (ctrl && editorIF->isSelecting()) editorIF->endSelect(); editorIF->caretRight (); break; } case SWindowListener::Key_M: case SWindowListener::Key_m: if (ctrl) { editorIF->endSelect(); editorIF->setCursorIndex(SCursorIndex(b.textIndex.line, 0)); STextIndex mba = editorIF->getIndexAfterLineBreak (); ba = SCursorIndex (mba.line, mba.index); erasedString = editorIF->eraseText(mba); if (cleared) return; if (erasedString.size() != 0) { a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Erase, editorIF->getDirection (), embd, erasedString, b, a, ba)); } break; } case SWindowListener::Key_R: case SWindowListener::Key_r: if (ctrl) { redo (); break; } case SWindowListener::Key_U: case SWindowListener::Key_u: if (ctrl) { undo (); break; } case SWindowListener::Key_v: if (ctrl) { if (editorIF->isSelecting()) editorIF->endSelect(); pasteText(b); return; } case SWindowListener::Key_V: if (ctrl|meta) { if (editorIF->isSelecting()) editorIF->endSelect(); pasteText (b); return; } case SWindowListener::Key_X: case SWindowListener::Key_x: if (ctrl | meta) { /* switch - delete */ std = SUndo::SS_EraseSelect; STextIndex mba = editorIF->getSelectedIndex(true); erasedString = editorIF->eraseSelectedText(); if (cleared) return; if (erasedString.size() != 0) { a = editorIF->getCursorIndex(); add (SUndo(std, editorIF->getDirection (), embd, erasedString, b, a, ba)); } break; } case SWindowListener::Key_Send: default: if (vimode && key != SWindowListener::Key_Send && s == ":" && !editorIF->isEditable()) { /* push the focus to the command window. */ editorIF->focusOut(); break; } SEncoder enc; SV_UCS4 ustr = enc.decode(s); while (ustr.size() && editorIF->addComposing(ustr[0])) { std = SUndo::SS_ComposeOne; a = editorIF->getCursorIndex(); SS_UCS4 u4 = ustr[0]; /* hack, string stores u4 */ add (SUndo(std, editorIF->getDirection (), embd, SString((char*)&u4, sizeof (u4)), a, a, a)); ustr.remove (0); } SString sstr = enc.encode (ustr); if (sstr.size()) { b = editorIF->getCursorIndex(); editorIF->insertDirtyText(sstr); ba = editorIF->getCursorIndex(); a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Insert, editorIF->getDirection (), embd, sstr, b, a, ba)); } else /* to update glyph info */ { a = editorIF->getCursorIndex(); editorIF->setCursorIndex(a); } } } /** * called when a key was released. */ void SEditor::keyReleased (SWindowListener::SKey key, const SString& s, bool ctrl, bool shift, bool meta) { if (editorIF == 0) return; if (key==SWindowListener::Key_Meta_R || key == SWindowListener::Key_Meta_L || key == SWindowListener::Key_Alt_R || key==SWindowListener::Key_Alt_L || key == SWindowListener::Key_Control_L||key==SWindowListener::Key_Control_R || key == SWindowListener::Key_Shift_R || key==SWindowListener::Key_Shift_L) { editorIF->endSelect(); return; } } /** * called when a mouse button was pressed. */ void SEditor::buttonPressed (int button, const SCursorIndex& index) { if (editorIF == 0) return; editorIF->deselectText(); if (button == 1) { pasteText(editorIF->getCursorIndex()); return; } /*mousewheel*/ if (button == 4) { editorIF->caretDown(); } else if (button == 3) { editorIF->caretUp(); } else { editorIF->setCursorIndex (index); editorIF->startSelect(); } } /** * paste a text ftom clip */ void SEditor::pasteText (const SCursorIndex& index) { if (editorIF == 0) return; editorIF->deselectText(); editorIF->setCursorIndex(index); SCursorIndex b = index; /* stop input methods */ editorIF->insertClipboardText(); SCursorIndex ba = editorIF->getCursorIndex(); SString s = editorIF->getText (b.getTextIndex(), ba.getTextIndex()); SCursorIndex a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Insert, editorIF->getDirection (), editorIF->getDocumentEmbedding(), s, b, a, ba)); } /** * Set clean text. */ void SEditor::insertText (const SString& text) { if (editorIF == 0) return; editorIF->deselectText(); SCursorIndex b = editorIF->getCursorIndex(); editorIF->insertText(text); SCursorIndex ba = editorIF->getCursorIndex(); SString s = text; SCursorIndex a = editorIF->getCursorIndex(); add (SUndo(SUndo::SS_Insert, editorIF->getDirection (), editorIF->getDocumentEmbedding(), s, b, a, ba)); } /** * called when a mouse button was released. */ void SEditor::buttonReleased (int button, const SCursorIndex& index) { if (editorIF == 0) return; if (button == 1) { return; } editorIF->selectText (index); editorIF->endSelect (); } /** * called when a mouse button was dragged. */ void SEditor::buttonDragged (int button, const SCursorIndex& index) { if (button == 1) { return; } if (editorIF == 0) return; editorIF->selectText (index); } /** * called when a mouse button was nulti-clicked. * It can come only if button was already released. */ void SEditor::multiClicked (int button, const SCursorIndex& index, int count) { if (editorIF == 0) return; if (button == 1) { return; } editorIF->selectText (index); editorIF->endSelect (); if (count == 2) { editorIF->selectWord (); } else if (count > 2) { editorIF->selectLine (); } } /** * This sets a set of input methods that can be activated with F1-F12. */ void SEditor::setInputMethods (const SStringVector& in) { inputMethods = in; } /** * set editor mode. */ void SEditor::setVI (bool vi) { vimode = vi; } /** * This sets a set of fonts that can be activated with F1-F12. */ void SEditor::setFonts (const SStringVector& in) { fonts = in; } /** * An FKEY was pressed. * @param num *
    *
  • F1 - 0
  • *
  • F2 - 1
  • *
  • Fn - n-1
  • *
*/ void SEditor::fKey(int num, bool ctrl) { if (ctrl) { if (fonts.size() >= (unsigned int) num+1) { editorIF->setFont(fonts[num]); } } else { if (inputMethods.size() >= (unsigned int) num+1) { editorIF->setInputMethod(inputMethods[num]); } } } /** * Try to undo * @return false in case it can not be undone. */ bool SEditor::undo() { //fprintf (stderr, "undo\n"); if (editorIF == 0) return false; /* clear state should be visible */ if (editorIF->clearState()) return true; if (undoIndex == 0) { //fprintf (stderr, "SEditor::nothing to undo - undoindex\n"); return false; } if (!editorIF->isEditable()) { return false; } if (editorIF->isSelecting()) { // fprintf (stderr, "SEditor::can not undo while selecting.\n"); return false; } undoIndex--; SUndo u = undoBuffer[undoIndex]; //fprintf (stderr, "Undo:%d.\n", u.type); switch (u.type) { case SUndo::SS_Insert: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.beforeAfter); editorIF->eraseText (u.before.getTextIndex()); editorIF->setDirection(u.direction); break; case SUndo::SS_Erase: case SUndo::SS_EraseOne: case SUndo::SS_BackSpaceOne: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.beforeAfter); editorIF->setCursorIndex(u.after); editorIF->insertText(u.string, false); editorIF->setCursorIndex(u.before); break; case SUndo::SS_ComposeOne: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.after); editorIF->setDirection(u.direction); editorIF->removeComposing(); editorIF->setCursorIndex(u.after); editorIF->setDirection(u.direction); /* compose does not move caret */ break; case SUndo::SS_EraseSelect: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.after); editorIF->insertText(u.string, false); editorIF->startSelect(); /* this is the sleection spot */ editorIF->selectText(u.after); editorIF->endSelect(); editorIF->setCursorIndex(u.after); break; } return true; } /** * Try to redo * @return false in case it can not be undone. */ bool SEditor::redo() { //fprintf (stderr, "redo\n"); if (editorIF == 0) return false; editorIF->clearState(); if (undoIndex == undoBuffer.size()) { //fprintf (stderr, "SEditor::redo ends here.\n"); return false; } if (!editorIF->isEditable()) return false; if (editorIF->isSelecting()) { //fprintf (stderr, "SEditor::can not redo while selecting.\n"); return false; } SUndo u = undoBuffer[undoIndex]; undoIndex++; //fprintf (stderr, "redo:%d.\n", u.type); switch (u.type) { case SUndo::SS_Insert: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.before); editorIF->insertText(u.string, false); break; case SUndo::SS_Erase: case SUndo::SS_EraseSelect: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.after); editorIF->eraseText(u.beforeAfter.getTextIndex()); break; case SUndo::SS_BackSpaceOne: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.before); editorIF->backspace(); break; case SUndo::SS_EraseOne: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.before); editorIF->erase(); break; case SUndo::SS_ComposeOne: editorIF->setDocumentEmbedding(u.embedding); editorIF->setCursorIndex(u.after); editorIF->setDirection(u.direction); { const SS_UCS4* u4 = (const SS_UCS4*) u.string.array(); editorIF->addComposing(u4[0]); editorIF->setCursorIndex(u.after); } break; } return true; } /** * add an item to undo buffer * @param u is the new item. * TODO: clear buffer after some size. */ void SEditor::add (const SUndo& u) { if (undoBuffer.size() != undoIndex) { if (undoIndex==0) { undoBuffer.clear(); } else { undoBuffer.truncate(undoIndex); } undoIndex = undoBuffer.size(); } undoBuffer.append (u); undoIndex++; } /** * clear the undo buffer. */ void SEditor::clearUndo() { undoBuffer.clear(); undoIndex = 0; } void SEditor::clear () { cleared = true; vimode = false; undoIndex = 0; undoBuffer.clear(); } void SEditor::setParagraphSeparator (const SString& _paragBreak) { paragBreak = _paragBreak; } SString SEditor::getParagraphSeparator () const { return SString (paragBreak); }