Bug 132846

Summary: Pasting text over selected text does not work
Product: [Unmaintained] kbabel Reporter: Sander Koning <sanderkoning>
Component: generalAssignee: Stanislav Visnovsky <visnovsky>
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: Bugfix

Description Sander Koning 2006-08-23 10:07:52 UTC
Version:            (using KDE KDE 3.5.2)

When pasting text over selected text in KBabel, the editor will make a small mess of it.
It seems like the position at which the text is inserted is calculated incorrectly, with results like "This text con&entity;tains an".
Comment 1 Stephan Johach 2006-11-08 18:38:59 UTC
I am currently investigating this and found a reproducable behaviour:

Select a string, e.g. in docmessages/kdebase/kate.po

<author>&Anders.Lund; &Anders.Lund.mail;</author>

Now mark the area between <author> and </author> beginning from the LEFT (!) 
side.

Press Ctrl-M

Now you get:

<author></author></author>

That is not really wrong, but now go the next entry and then again back to the 
changed entry. You now get the following:

<author></author>                       </author>

The entry is broken now, with whitespace in between.

Now reload the file to it's initial state an go to the same entry.

But now mark the above mentioned text frem RIGHT to LEFT.

You will get:

<author>&Anders.Lund;</author>

But this time the entry is not broken when you leave it and come back again. 

Looks like the problem ist, that KBabel takes a wrong offset when a selection 
is marked from LEFT to RIGHT, so the text is changed wrong internally.

Can you confirm this behaviour? Is this similar to what you did?

I am not sure if I can find a solution, but I am trying to.
Comment 2 Sander Koning 2006-11-08 18:47:04 UTC
Confirmed. I have tried it with "<keyword>KDE</keyword>":

- Mark "KDE" from left to right and press Ctrl-M. Both the msgstr panel and the translation list show "<keyword></keyword></keyword>". 
- Press PageDown, PageUp: the translation list doesn't change, but the msgstr panel shows "<keyword></k</keyword>eyword>".

- Mark "KDE" from right to left and press Ctrl-M. Both the msgstr panel and the translation list show "<keyword></keyword></keyword>". 
- Press PageDown, PageUp: the translation list nor the msgstr changes.
Comment 3 Stephan Johach 2006-11-10 17:09:55 UTC
Created attachment 18492 [details]
Bugfix

I provide a patch here which fixes the problem for me. Can you please apply the
patch and test it. If you think it works correctly and you get no side effects
I'll apply to stable branch.
Comment 4 Stephan Johach 2006-11-12 10:31:18 UTC
SVN commit 604274 by johach:

Fix broken replacement of marked text with e.g. ctrl-m.
BUG:132846


 M  +2 -0      hidingmsgedit.h  
 M  +1 -1      kbabelview2.cpp  
 M  +44 -3     mymultilineedit.cpp  
 M  +22 -0     mymultilineedit.h  


--- branches/KDE/3.5/kdesdk/kbabel/kbabel/hidingmsgedit.h #604273:604274
@@ -72,6 +72,8 @@
 	{ _currentEdit->getCursorPosition(para,index); }
   int currentIndex() const
 	{ return _currentEdit->currentIndex(); }
+  int beginOfLastMarkedText() const
+    { return _currentEdit->beginOfLastMarkedText(); }
   virtual void setFont ( const QFont & );
   void setCurrentColor(const MsgMultiLineEdit::TextColor color);
   bool spacePoints() const { return _currentEdit->spacePoints(); }
--- branches/KDE/3.5/kdesdk/kbabel/kbabel/kbabelview2.cpp #604273:604274
@@ -322,7 +322,7 @@
 {
     TagExtractor extractor;
 
-    int offset = msgstrEdit->currentIndex();
+    int offset = msgstrEdit->beginOfLastMarkedText(); //msgstrEdit->currentIndex();
 
     QString s = (*_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm())).left(offset);
 
--- branches/KDE/3.5/kdesdk/kbabel/kbabel/mymultilineedit.cpp #604273:604274
@@ -63,16 +63,41 @@
 using namespace KBabel;
 
 MyMultiLineEdit::MyMultiLineEdit(int ID, QWidget* parent,const char* name)
-                :KTextEdit(parent,name), emitUndo(true), _firstChangedLine(0), 
-		_lastChangedLine(0), _lastParagraph(0), 
-		_lastParagraphOffset(0), _dontUpdate(false), _myID (ID),
+                :KTextEdit(parent,name), emitUndo(true), 
+		_firstChangedLine(0), 
+		_lastChangedLine(0), 
+        	_lastParagraph(0), 
+		_lastParagraphOffset(0), 
+		_lastSelectionStart(-1), 
+		_lastSelectionEnd(-1),
+		_dontUpdate(false), _myID (ID),
 		 _menu(0), _overwrite(false)
 {
    setUndoRedoEnabled(false); // we handle this ourselves
    setWordWrap( WidgetWidth );
    viewport()->setAcceptDrops( false ); // we need our parent to get drops
+
+   connect(this, SIGNAL(selectionChanged()), this, SLOT( onSelectionChanged() ) );
 }
 
+void MyMultiLineEdit::onSelectionChanged()
+{
+    kdDebug(KBABEL) << "MyMultiLineEdit::onSelectionChanged" << endl;
+    int parFrom, parTo, indexFrom, indexTo;
+    if ( hasSelectedText() ) {
+        getSelection( &parFrom, &indexFrom, &parTo, &indexTo );
+        kdDebug(KBABEL) << "parFrom=" << parFrom << "indexFrom=" << indexFrom << "parTo=" << parTo << "indexTo=" << indexTo << endl;
+        _lastSelectionStart = beginOfMarkedText();
+    }
+    else
+    {
+        _lastSelectionStart = -1; // no selection
+        _lastSelectionEnd = -1;
+    }
+
+    kdDebug(KBABEL) << "_lastSelectionStart=" << _lastSelectionStart << endl;
+}
+
 void MyMultiLineEdit::processCommand(EditCommand* cmd, bool undo)
 {
    if(cmd->terminator()!=0)
@@ -145,6 +170,22 @@
    emitCursorPosition();
 }
 
+int MyMultiLineEdit::beginOfLastMarkedText()
+{
+    if ( _lastSelectionStart != -1 )
+        return _lastSelectionStart;
+    else
+        return currentIndex();
+}
+
+int MyMultiLineEdit::endOfLastMarkedText()
+{
+    if ( _lastSelectionEnd != -1 )
+        return _lastSelectionEnd;
+    else
+        return currentIndex();
+}
+
 int MyMultiLineEdit::beginOfMarkedText()
 {
 	int beginX=0;
--- branches/KDE/3.5/kdesdk/kbabel/kbabel/mymultilineedit.h #604273:604274
@@ -65,6 +65,20 @@
 	*/
    int beginOfMarkedText();
 
+    /** 
+    * @returns the position in text, where the last marked text began
+    * or the current cursor position if there was no marked text.
+    * This is used for getting the start position for a text replacement
+    */
+   int beginOfLastMarkedText();
+
+    /** 
+    * @returns the position in text, where the last marked text ended
+    * or the current cursor position if there was no marked text.
+    * This is used for getting the end position for a text replacement
+    */
+   int endOfLastMarkedText();
+
    virtual void insertAt ( const QString & s, int line, int col, bool mark = false );
    virtual void removeLine ( int line );
 
@@ -92,6 +106,7 @@
    bool isOverwriteMode() { return _overwrite; }    
 
 public slots:
+   
    virtual void clear();
    virtual void paste();
    virtual void setReadOnly(bool on);
@@ -99,6 +114,8 @@
    virtual void setText(const QString& s);
    virtual void doKeyboardAction( KeyboardAction action );
    virtual void removeSelectedText(int selNum = 0);
+
+   virtual void onSelectionChanged();
    
    /**
    reimplemented overwrite mode, since QTextEdit handles this internally and does
@@ -128,6 +145,11 @@
    uint _lastParagraph;
    uint _lastParagraphOffset;
 
+   /* We save the last selection positions. This is needed when a tag is inserted to get the
+      left cursor position of the originally used selection */
+   int _lastSelectionStart;
+   int _lastSelectionEnd;
+
    /* flag to skip any work on updating, since it will be more changes */
    bool _dontUpdate;
 
Comment 5 Sander Koning 2006-11-13 09:27:09 UTC
I've got everything out of Kubuntu packages atm, but I will try to think of testing the patch when I've got time to grab the sources and compile