[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    [PATCH] Textarea search, and spelling->KStdAction
From:       George Staikos <staikos () kde ! org>
Date:       2003-09-25 7:29:24
[Download RAW message or body]

Attached is a patch that does two things:

1) Converts the spell check menu item to a standard action.  This way if it 
gets an accelerator in the future, it will "just work".

2) Most importantly, I implemented: 
http://ask.slashdot.org/article.pl?sid=03/09/24/201231&mode=thread&tid=126&tid=185&tid=95

   It isn't *perfect* yet which is why I did not apply this patch.  I would 
like some testing, and perhaps some help.  This patch doesn't support regexps 
at all, and I think the "find" is a bit clunky still (there is no "Find Next" 
and trying to find again finds the same hit over again).  In general it works 
though.


  Oh if someone has a slashdot account and cares, feel free to post a link to 
this patch to show them that 49 (at this point) Slashdotters can talk about a 
feature and form a committee in the same time that one person can implement 
it.  Reminds me of a joke about lightbulbs... :)

-- 
George Staikos
KDE Developer				http://www.kde.org/
Staikos Computing Services Inc.		http://www.staikos.net/

["textarea-search.patch" (text/x-diff)]

Index: render_form.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/rendering/render_form.cpp,v
retrieving revision 1.235
diff -u -3 -p -r1.235 render_form.cpp
--- render_form.cpp	9 Sep 2003 16:31:55 -0000	1.235
+++ render_form.cpp	25 Sep 2003 07:17:12 -0000
@@ -23,13 +23,17 @@
  * $Id: render_form.cpp,v 1.235 2003/09/09 16:31:55 pletourn Exp $
  */
 
-#include <kdebug.h>
-#include <klocale.h>
-#include <kfiledialog.h>
 #include <kcompletionbox.h>
 #include <kcursor.h>
-#include <kspell.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kfinddialog.h>
 #include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kreplacedialog.h>
+#include <kspell.h>
+#include <kwin.h>
 
 #include <qstyle.h>
 
@@ -289,15 +293,22 @@ LineEditWidget::LineEditWidget(DOM::HTML
     : KLineEdit(parent), m_input(input), m_view(view), m_spell(0)
 {
     setMouseTracking(true);
+    KActionCollection *ac = new KActionCollection(this);
+    m_spellAction = KStdAction::spelling( this, SLOT( slotCheckSpelling() ), ac );
 }
 
 LineEditWidget::~LineEditWidget()
 {
     delete m_spell;
+    m_spell = 0L;
 }
 
 void LineEditWidget::slotCheckSpelling()
 {
+    if ( text().isEmpty() ) {
+        return;
+    }
+
     delete m_spell;
     m_spell = new KSpell( this, i18n( "Spell Checking" ), this, SLOT( \
slotSpellCheckReady( KSpell *) ), 0, true, true);  
@@ -346,29 +357,34 @@ void LineEditWidget::slotSpellCheckDone(
 QPopupMenu *LineEditWidget::createPopupMenu()
 {
     QPopupMenu *popup = KLineEdit::createPopupMenu();
-    if ( !popup )
+
+    if ( !popup ) {
         return 0L;
+    }
+
     connect( popup, SIGNAL( activated( int ) ),
              this, SLOT( extendedMenuActivated( int ) ) );
 
     if (m_input->autoComplete()) {
         popup->insertSeparator();
         int id = popup->insertItem( i18n("Clear &History"), ClearHistory );
-        if (!completionObject())
-            popup->setItemEnabled( id, false);
+        if (!completionObject()) {
+            popup->setItemEnabled( id, false );
+        }
     }
 
     if (echoMode() == QLineEdit::Normal &&
         !isReadOnly()) {
         popup->insertSeparator();
-        int id = popup->insertItem( SmallIcon( "spellcheck" ), i18n( "Check \
                Spelling" ), this, SLOT( slotCheckSpelling() ) );
-        if( text().isEmpty() )
-            popup->setItemEnabled( id, false );
+
+        m_spellAction->plug(popup);
+        m_spellAction->setEnabled( !text().isEmpty() );
     }
 
     return popup;
 }
 
+
 void LineEditWidget::extendedMenuActivated( int id)
 {
     switch ( id )
@@ -1248,7 +1264,7 @@ void RenderSelect::updateSelection()
 // -------------------------------------------------------------------------
 
 TextAreaWidget::TextAreaWidget(int wrap, QWidget* parent)
-    : KTextEdit(parent)
+    : KTextEdit(parent), m_findDlg(0), m_repDlg(0)
 {
     setCheckSpellingEnabled( true );
 
@@ -1266,7 +1282,191 @@ TextAreaWidget::TextAreaWidget(int wrap,
     setTextFormat(QTextEdit::PlainText);
     setAutoMask(true);
     setMouseTracking(true);
+
+    KActionCollection *ac = new KActionCollection(this);
+    m_findAction = KStdAction::find( this, SLOT( slotFind() ), ac );
+    m_replaceAction = KStdAction::replace( this, SLOT( slotReplace() ), ac );
+}
+
+
+TextAreaWidget::~TextAreaWidget()
+{
+    delete m_repDlg;
+    m_repDlg = 0L;
+    delete m_findDlg;
+    m_findDlg = 0L;
+}
+
+
+QPopupMenu *TextAreaWidget::createPopupMenu(const QPoint& pos)
+{
+    QPopupMenu *popup = KTextEdit::createPopupMenu(pos);
+
+    if ( !popup ) {
+        return 0L;
+    }
+
+    if (!isReadOnly()) {
+        popup->insertSeparator();
+
+        m_findAction->plug(popup);
+        m_findAction->setEnabled( !text().isEmpty() );
+
+        m_replaceAction->plug(popup);
+        m_replaceAction->setEnabled( !text().isEmpty() );
+    }
+
+    return popup;
+}
+
+
+void TextAreaWidget::slotFindNext()
+{
+    int index = 0, para = 0;
+    bool replace = m_repDlg && sender() == m_repDlg;
+    KFindDialog *dlg = 0L;
+
+    if (replace) {
+        dlg = m_repDlg;
+    } else {
+        dlg = m_findDlg;
+    }
+
+    if (!dlg) {
+        // Should really assert()
+        return;
+    }
+
+    QString pattern = dlg->pattern();
+    long options = dlg->options();
+
+    if (pattern.isEmpty()) {
+        dlg->hide();
+        return;
+    }
+
+    if (options & KFindDialog::FromCursor) {
+        getCursorPosition(&para, &index);
+        if (options & KFindDialog::FindBackwards) {
+            if (index == 0 && para == 0) {
+                dlg->hide();
+                return;
+            } else {
+                moveCursor(MoveBackward, false);
+            }
+        } else {
+            if (para == paragraphs() - 1 && index == paragraphLength(paragraphs() - \
1) - 1) { +                dlg->hide();
+                return;
+            } else {
+                moveCursor(MoveForward, false);
+            }
+        }
+    } else if (options & KFindDialog::FindBackwards) {
+        para = paragraphs() - 1;
+        index = paragraphLength(para) - 1;
+    }
+
+    //kdDebug() << "Searching for " << pattern << " at " << para << " "
+    //          << index << ",  case: "
+    //          << bool(options & KFindDialog::CaseSensitive)
+    //          << ", whole words: "
+    //          << bool(options & KFindDialog::WholeWordsOnly)
+    //          << ", backwards: "
+    //          << bool(options & KFindDialog::FindBackwards) << endl;
+
+    bool rc = find(pattern,
+                   options & KFindDialog::CaseSensitive,
+                   options & KFindDialog::WholeWordsOnly,
+                   !(options & KFindDialog::FindBackwards),
+                   &para,
+                   &index);
+
+    if (rc) {
+        setCursorPosition(para, index);
+        ensureCursorVisible();
+	dlg->setOptions(options | KFindDialog::FromCursor);
+        dlg->hide();
+        if (replace) {
+            bool prompt = m_repDlg->options() & KReplaceDialog::PromptOnReplace;
+            while (rc) {
+                int epara = 0, eindex = 0;
+                int forwardOffset = 0;
+
+                getSelection(&para, &index, &epara, &eindex);
+
+                QString replacement = m_repDlg->replacement();
+                if (prompt) {
+                    int rc = KMessageBox::questionYesNo(this, i18n("Replace '%1' \
with '%2'?").arg(pattern).arg(replacement)); +                    if (rc == \
KMessageBox::Yes) { +                        removeSelectedText();
+                        insertAt(replacement, para, index);
+                        forwardOffset = replacement.length();
+                    } else {
+                        forwardOffset = 1;
+                    }
+                } else {
+                    removeSelectedText();
+                    insertAt(replacement, para, index);
+                    forwardOffset = replacement.length();
+                }
+
+                if (options & KFindDialog::FindBackwards) {
+                    if (para == 0 && index == 0) {
+                        break;
+                    }
+                    setCursorPosition(para, index);
+                    for (int i = 0; i < pattern.length(); ++i) {
+                        moveCursor(MoveBackward, false);
+                    }
+                } else {
+                    setCursorPosition(para, index + forwardOffset);
+                }
+
+                rc = find(pattern,
+                          options & KFindDialog::CaseSensitive,
+                          options & KFindDialog::WholeWordsOnly,
+                          !(options & KFindDialog::FindBackwards),
+                          0, 0);
+            }
+        }
+    } else {
+        dlg->hide();
+        return;
+    }
 }
+
+
+void TextAreaWidget::slotFind()
+{
+    if( text().isEmpty() )  // saves having to track the text changes
+        return;
+
+    if ( m_findDlg ) {
+      KWin::setActiveWindow( m_findDlg->winId() );
+    } else {
+      m_findDlg = new KFindDialog(false, this, "KHTML Text Area Find Dialog");
+      connect( m_findDlg, SIGNAL(okClicked()), this, SLOT(slotFindNext()) );
+    }
+    m_findDlg->show();
+}
+
+
+void TextAreaWidget::slotReplace()
+{
+    if( text().isEmpty() )  // saves having to track the text changes
+        return;
+
+    if ( m_repDlg ) {
+      KWin::setActiveWindow( m_repDlg->winId() );
+    } else {
+      m_repDlg = new KReplaceDialog(this, "KHTMLText Area Replace Dialog", 0,
+                                    QStringList(), QStringList(), false);
+      connect( m_repDlg, SIGNAL(okClicked()), this, SLOT(slotFindNext()) );
+    }
+    m_repDlg->show();
+}
+
 
 bool TextAreaWidget::event( QEvent *e )
 {
Index: render_form.h
===================================================================
RCS file: /home/kde/kdelibs/khtml/rendering/render_form.h,v
retrieving revision 1.99
diff -u -3 -p -r1.99 render_form.h
--- render_form.h	7 Sep 2003 20:52:28 -0000	1.99
+++ render_form.h	25 Sep 2003 07:17:13 -0000
@@ -47,6 +47,9 @@ class QListboxItem;
 
 class KHTMLPartBrowserExtension;
 class KSpell;
+class KFindDialog;
+class KReplaceDialog;
+class KAction;
 
 namespace DOM {
     class HTMLFormElementImpl;
@@ -260,6 +263,7 @@ private:
     DOM::HTMLInputElementImpl* m_input;
     KHTMLView* m_view;
     KSpell *m_spell;
+    KAction *m_spellAction;
 };
 // -------------------------------------------------------------------------
 
@@ -397,15 +401,25 @@ protected slots:
 };
 
 // -------------------------------------------------------------------------
-
 class TextAreaWidget : public KTextEdit
 {
     Q_OBJECT
 public:
     TextAreaWidget(int wrap, QWidget* parent);
+    virtual ~TextAreaWidget();
 
 protected:
     virtual bool event (QEvent *e );
+    virtual QPopupMenu *createPopupMenu(const QPoint& pos);
+private slots:
+    void slotFind();
+    void slotFindNext();
+    void slotReplace();
+private:
+    KFindDialog *m_findDlg;
+    KReplaceDialog *m_repDlg;
+    KAction *m_findAction;
+    KAction *m_replaceAction;
 };
 
 



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic