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

List:       kde-pim
Subject:    [Kde-pim] Towards better nested list handling in KMail
From:       Stephen Kelly <steveire () gmail ! com>
Date:       2008-03-16 12:59:50
Message-ID: frj5k3$9mj$1 () ger ! gmane ! org
[Download RAW message or body]

Hi,

This is another feature I've been working on for kjots.

KMEditor supports lists currently, but not nested lists. I've been
experiementing with adding a DoTheRightThing nested list feature in kjots
and kmail.

To try it out,

Apply the attached patch, and try out the new actions.

Here's what works and doesn't work using the attached screenshot:

1) Make a list with the list style drop down.
2) Increase the indent of some items. All numbers are recalculated
correctly.
3) Decrease the indent of some items to zero. This splits two lists.
4) Append or prepend adjactent items to the list. The bounding margin below
the list is preserved.
5) Change the type of list item of a certain level in a list.

~~ This is where things start to break.
6) Press enter after 'seven' and the bounding margin is not handled
correctly.
7) Take an item out of the list using the backspace key and the list is not
reformatted.

8) Doing some action on the list reformats it and fixes both of the above.
The user shouldn't have to do a workaround like that though.

In reality I think the QTextList needs some new API to add this stuff
cleanly and make the reformatList method unneccessary. I had a look at the
code and it looks like qt code is too complex for me at the moment to send
a patch to them. I'll fill a wishlist item with them, but as it won't be
high priority I'd prefer to send a patch with it.

Does anyone know enough about the QTextList section of Qt to give me a
kickstart on this?

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

Index: kmail/kmcomposerui.rc
===================================================================
--- kmail/kmcomposerui.rc	(revision 786223)
+++ kmail/kmcomposerui.rc	(working copy)
@@ -1,4 +1,4 @@
-<!DOCTYPE kpartgui ><kpartgui version="392" name="kmcomposer" >
+<!DOCTYPE kpartgui ><kpartgui version="393" name="kmcomposer" >
  <MenuBar>
   <Menu noMerge="1" name="file" >
    <text>&amp;Message</text>
@@ -100,7 +100,6 @@
   <Action name="encrypt_message" />
  </ToolBar>
  <ToolBar noMerge="1" newline="true" hidden="true" enable="0" name="htmlToolBar" \
                ><text>HTML Toolbar</text>
-  <Action name="text_list" />
   <Action name="text_font" />
   <Action name="text_size" />
   <Action name="format_reset" />
@@ -111,5 +110,8 @@
   <Action name="align_left" />
   <Action name="align_center" />
   <Action name="align_right" />
+  <Action name="text_list" />
+  <Action name="indent_more" />
+  <Action name="indent_less" />
  </ToolBar>
 </kpartgui>
Index: kmail/kmcomposewin.h
===================================================================
--- kmail/kmcomposewin.h	(revision 786223)
+++ kmail/kmcomposewin.h	(working copy)
@@ -745,6 +745,8 @@
     KToggleAction *mDictionaryAction, *mSnippetAction;
 
     KPIM::KMStyleListSelectAction *listAction;
+    KAction *indentMoreAction;
+    KAction *indentLessAction;
     KFontAction *fontAction;
     KFontSizeAction *fontSizeAction;
     KToggleAction *alignLeftAction, *alignCenterAction, *alignRightAction;
Index: kmail/kmcomposewin.cpp
===================================================================
--- kmail/kmcomposewin.cpp	(revision 786223)
+++ kmail/kmcomposewin.cpp	(working copy)
@@ -1390,9 +1390,19 @@
 
   listAction = new KMStyleListSelectAction( i18n("Select Style"), this );
   actionCollection()->addAction( "text_list", listAction );
-
   connect( listAction, SIGNAL( applyStyle(QTextListFormat::Style) ),
            mEditor, SLOT( slotChangeParagStyle(QTextListFormat::Style) ) );
+
+  indentMoreAction = actionCollection()->addAction("indent_more");
+  indentMoreAction->setText(i18n("Increase Indent"));
+  indentMoreAction->setIcon(KIcon("format-indent-more"));
+  connect( indentMoreAction, SIGNAL( triggered() ), mEditor, SLOT( slotIndentMore() \
) ); +
+  indentLessAction = actionCollection()->addAction("indent_less");
+  indentLessAction->setText(i18n("Decrease Indent"));
+  indentLessAction->setIcon(KIcon("format-indent-less"));
+  connect( indentLessAction, SIGNAL( triggered() ), mEditor, SLOT( slotIndentLess() \
) ); +  
   fontAction = new KFontAction(i18n("Select Font"), this);
   actionCollection()->addAction("text_font", fontAction );
   connect( fontAction, SIGNAL( triggered( const QString& ) ),
Index: libkdepim/kmeditor.cpp
===================================================================
--- libkdepim/kmeditor.cpp	(revision 786223)
+++ libkdepim/kmeditor.cpp	(working copy)
@@ -51,7 +51,7 @@
 #include <KDirWatch>
 #include <KTemporaryFile>
 #include <KCursor>
-#include <sonnet/configdialog.h><n
+#include <sonnet/configdialog.h>
 
 //qt includes
 #include <QApplication>
@@ -119,6 +119,9 @@
     // Each pair is the index of the start- and end position of the signature.
     QList< QPair<int,int> > signaturePositions( const KPIMIdentities::Signature &sig \
) const;  
+    // Reformats lists on, above and below the cursor by renesting and rebuilding
+    void reformatList();
+    
     // Data members
     QMap<QString,QStringList> replacements;
     QString extEditorPath;
@@ -248,6 +251,103 @@
   q->mergeCurrentCharFormat( format );
 }
 
+
+void KMeditorPrivate::reformatList()
+{
+  QTextCursor cursor = q->textCursor();
+  if ( !cursor.currentList() ){
+    int initialPosition = cursor.position();
+    int initialAnchor = cursor.anchor();
+    int upperPosition;
+    int lowerPosition;
+  
+    if (initialPosition != initialAnchor){
+      if (initialPosition > initialAnchor){
+        lowerPosition = initialAnchor;
+        upperPosition = initialPosition;
+      }else{
+        lowerPosition = initialPosition;
+        upperPosition = initialAnchor;
+      }
+    }
+    else {
+      lowerPosition = upperPosition = initialPosition;
+    }
+
+    cursor.setPosition(lowerPosition);
+    cursor.movePosition(QTextCursor::PreviousBlock);
+    if (cursor.currentList()){
+      q->setTextCursor(cursor);
+      reformatList();
+    }
+
+    cursor.setPosition(upperPosition);
+    cursor.movePosition(QTextCursor::NextBlock);
+    if (cursor.currentList()){
+      q->setTextCursor(cursor);
+      reformatList();
+    }
+    cursor.setPosition(initialAnchor, QTextCursor::MoveAnchor);
+    cursor.setPosition(initialPosition, QTextCursor::KeepAnchor);
+    q->setTextCursor(cursor);
+    return;
+  }
+
+  QTextBlock block = cursor.block();
+
+  // Start at the top of the list
+  while ( block.previous().textList() != 0 ){
+    block = block.previous();
+  }
+
+  QTextBlockFormat blockFmt = block.blockFormat();
+  blockFmt.setTopMargin(12);
+  blockFmt.setBottomMargin(0);
+  cursor.setPosition(block.position());
+  cursor.setBlockFormat(blockFmt);
+  block = cursor.block();
+
+  cursor.createList(cursor.currentList()->format());
+  QTextList* list = block.textList();
+  list->add(block);
+
+  QMap<int, QTextList *> nestedLists;
+  nestedLists.insert(list->format().indent(), list);
+
+  int indentLevel;
+  while ( block.next().textList() != 0 ) {
+    block = block.next();
+    list = block.textList();
+    indentLevel = list->format().indent();
+
+    foreach (int key, nestedLists.keys() ){
+      if (indentLevel < key){
+        nestedLists.remove(key);
+      }
+    }
+
+    if ( !nestedLists.contains(indentLevel) ) {
+      nestedLists.insert(indentLevel, list);
+    } else {
+      list = nestedLists.take(indentLevel);
+    }
+
+    blockFmt = block.blockFormat();
+    blockFmt.setTopMargin(0);
+    blockFmt.setBottomMargin(0);
+    cursor.setPosition(block.position());
+    cursor.setBlockFormat(blockFmt);
+
+    list->add(block);
+    nestedLists.insert(indentLevel, list);
+
+  }
+  blockFmt = block.blockFormat();
+  blockFmt.setBottomMargin(12);
+  cursor.setPosition(block.position());
+  cursor.setBlockFormat(blockFmt);
+}
+
 void KMeditor::dragEnterEvent( QDragEnterEvent *e )
 {
   if ( KPIM::MailList::canDecode( e->mimeData() ) ) {
@@ -444,49 +544,73 @@
 void KMeditor::slotChangeParagStyle( QTextListFormat::Style _style )
 {
   QTextCursor cursor = textCursor();
-  cursor.beginEditBlock();
-
-  // Create a list with the specified format
-  if ( _style != QTextListFormat::ListStyleUndefined ) {
-
-    QTextBlockFormat blockFmt = cursor.blockFormat();
+  if (_style != 0) {
+    QTextListFormat::Style style = _style;
+    QTextList *currentList = cursor.currentList();
     QTextListFormat listFmt;
+    cursor.beginEditBlock();
 
-    if ( cursor.currentList() ) {
-      listFmt = cursor.currentList()->format();
-    } else {
-      listFmt.setIndent( blockFmt.indent() + 1 );
-      blockFmt.setIndent( 0 );
-      cursor.setBlockFormat( blockFmt );
+    if (currentList){
+      listFmt = currentList->format();
+      listFmt.setStyle(style);
+      currentList->setFormat(listFmt);
     }
+    else {
+      listFmt.setStyle(style);
+      cursor.createList(listFmt);
+    }
 
-    listFmt.setStyle( _style );
-
-    cursor.createList( listFmt );
-    d->activateRichText();
+    cursor.endEditBlock();
+  } else {
+    QTextBlockFormat bfmt;
+    bfmt.setObjectIndex(-1);
+    cursor.setBlockFormat(bfmt);
   }
+  d->reformatList();
+}
 
-  // Remove the list formatting again
-  else {
-    QTextList *list = cursor.currentList();
-    if ( list ) {
 
-      QTextListFormat listFormat = list->format();
-      listFormat.setIndent( 0 );
-      list->setFormat( listFormat );
+void KMeditor::slotIndentMore()
+{
+  QTextCursor cursor = textCursor();
 
-      int count = list->count();
-      while ( count > 0 ) {
-        list->removeItem( 0 );
-        count--;
-      }
-    }
+  QTextListFormat listFmt;
+  if (!cursor.currentList()) {
+    QTextListFormat::Style style = QTextListFormat::ListDisc;
+    slotChangeParagStyle(style);
+  } else {
+    listFmt = cursor.currentList()->format();
+    listFmt.setIndent(listFmt.indent() + 1);
+
+    cursor.createList(listFmt);
+    d->reformatList();
   }
 
-  cursor.endEditBlock();
-  setFocus();
+//     onSelectionChanged();
 }
 
+void KMeditor::slotIndentLess()
+{
+  QTextCursor cursor = textCursor();
+  QTextList* currentList = cursor.currentList();
+  if ( !currentList )
+      return;
+  QTextListFormat listFmt;
+  listFmt = currentList->format();
+  if ( listFmt.indent() > 1 )
+  {
+    listFmt.setIndent(listFmt.indent() - 1);
+    cursor.createList(listFmt);
+    d->reformatList();
+  }else{
+    QTextBlockFormat bfmt;
+    bfmt.setObjectIndex(-1);
+    cursor.setBlockFormat(bfmt);
+    d->reformatList();
+  }
+//     onSelectionChanged();
+}
+
 void KMeditor::setColor( const QColor& col )
 {
   QTextCharFormat fmt;
Index: libkdepim/kmeditor.h
===================================================================
--- libkdepim/kmeditor.h	(revision 786223)
+++ libkdepim/kmeditor.h	(working copy)
@@ -287,6 +287,9 @@
     void slotAlignRight();
     void slotChangeParagStyle( QTextListFormat::Style _style );
 
+    void slotIndentMore();
+    void slotIndentLess();
+
     /**
      * Shows the spell checkdialog, where the user can perform spell checking
      * on the whole document.


["kmailbetterlists.png" (image/png)]

_______________________________________________
KDE PIM mailing list kde-pim@kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
KDE PIM home page at http://pim.kde.org/

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

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