On Donnerstag, 11. Oktober 2012 18:25:37 CEST, Jan Kundrát wrote:
> On 10/10/12 18:42, Thomas Lübking wrote:
>> I don't get the assert, but run into
>> qDebug()<< "drag-and-drop: mailbox not found";
>
> Are you sure you're building in the debug mode?
I didn't touch it, but "no" - diretcly aborting worked.
However in the current HEAD i don't get any debug out failure when dragging an
attached file into the attachment (while actually not entirely sure what this
is supposed to be good for ;-)
>> PS: need to be more careful about the ctrl+enter sending,
>> enter + ctrl+v seems to cause it as well...
>
> Could you please file a bug for this in the Trojita's issue
> tracker [1]? And could you please fix it as well? :)
I'm actually not sure whether that issue is related to trojitá at all, or
rather on my keyboard, X11 or kwin.
The code is ok, just that the ctrl modifier is apparently sometimes set while
it should not.
Attached is a couple of pending patches on top of the current master HEAD
1. pending file DND attachement support
2. the ctrl+enter patch (leave it if you fear it, but you'll not be able to
trigger mentioned behavior when waiting a couple of ms between releasing ctrl
and pressing enter)
3. input constrainments
4. automatic search reset on emptying the serachline
5. new take on the search GUI - even the present button solution is some sort
of squeezed in my netbook -> stashed stuff behind a popup toolbutton, including
a raw IMAP query builder.
On the IMAP queries: i tried that on some users and the major issue is that the
polish notation is completely incompatible with regular humans (aka "dummies"
;-)
The builder adds some placeholders and (partially) autoselects them and that
worked pretty good for the simple things (subject, since etc.) and even the
negation, but when i asked them to perform a juncted query ("or") ... well, we
all got a little upset =)
Right now i've however no better idea on this :-(
Cheers,
ThomasFrom a40364ac2264ef03b99e5b7fdf6981f2185dcb29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <[email protected]>
Date: Wed, 10 Oct 2012 00:19:46 +0200
Subject: [PATCH 1/6] add dnd support to file attachment
---
src/Gui/ComposeWidget.cpp | 16 +++++-
src/Gui/ComposeWidget.h | 3 ++
src/Gui/ComposeWidget.ui | 16 +++++-
src/Gui/ComposerAttachments.cpp | 64 +++++++++++++++++++++++
src/Gui/ComposerAttachments.h | 38 ++++++++++++++
src/Gui/ComposerTextEdit.cpp | 101 +++++++++++++++++++++++++++++++++++++
src/Gui/ComposerTextEdit.h | 51 +++++++++++++++++++
src/Gui/Gui.pro | 8 ++-
src/Imap/Model/MessageComposer.cpp | 14 ++++-
9 files changed, 303 insertions(+), 8 deletions(-)
create mode 100644 src/Gui/ComposerAttachments.cpp
create mode 100644 src/Gui/ComposerAttachments.h
create mode 100644 src/Gui/ComposerTextEdit.cpp
create mode 100644 src/Gui/ComposerTextEdit.h
diff --git a/src/Gui/ComposeWidget.cpp b/src/Gui/ComposeWidget.cpp
index 6c9a567..efdd514 100644
--- a/src/Gui/ComposeWidget.cpp
+++ b/src/Gui/ComposeWidget.cpp
@@ -58,6 +58,7 @@ ComposeWidget::ComposeWidget(MainWindow *parent) :
Q_ASSERT(m_mainWindow);
m_composer = new Imap::Mailbox::MessageComposer(m_mainWindow->imapModel(), this);
m_composer->setPreloadEnabled(shouldBuildMessageLocally());
+ m_composer->setSupportedDragActions( Qt::MoveAction|Qt::CopyAction|Qt::LinkAction );
ui->setupUi(this);
sendButton = ui->buttonBox->addButton(tr("Send"), QDialogButtonBox::AcceptRole);
@@ -66,14 +67,14 @@ ComposeWidget::ComposeWidget(MainWindow *parent) :
connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
ui->attachmentsView->setModel(m_composer);
connect(ui->attachButton, SIGNAL(clicked()), this, SLOT(slotAskForFileAttachment()));
- ui->attachmentsView->setAcceptDrops(true);
- ui->attachmentsView->setDropIndicatorShown(true);
ui->attachmentsView->setContextMenuPolicy(Qt::ActionsContextMenu);
m_actionRemoveAttachment = new QAction(tr("Remove"), this);
connect(m_actionRemoveAttachment, SIGNAL(triggered()), this, SLOT(slotRemoveAttachment()));
ui->attachmentsView->addAction(m_actionRemoveAttachment);
+ connect(ui->attachmentsView, SIGNAL(itemDroppedOut()), SLOT(slotRemoveAttachment()));
+
m_completionPopup = new QMenu(this);
m_completionPopup->installEventFilter(this);
connect (m_completionPopup, SIGNAL(triggered(QAction*)), SLOT(completeRecipient(QAction*)));
@@ -92,6 +93,8 @@ ComposeWidget::ComposeWidget(MainWindow *parent) :
QFont font(QLatin1String("x-trojita-terminus-like-fixed-width"));
font.setStyleHint(QFont::TypeWriter);
ui->mailText->setFont(font);
+
+ connect(ui->mailText, SIGNAL(urlsAdded(QList<QUrl>)), SLOT(slotAttachFiles(QList<QUrl>)));
}
ComposeWidget::~ComposeWidget()
@@ -573,6 +576,15 @@ void ComposeWidget::slotAskForFileAttachment()
}
}
+void ComposeWidget::slotAttachFiles(QList<QUrl> urls)
+{
+ foreach (const QUrl &url, urls) {
+ if (url.isLocalFile()) {
+ m_composer->addFileAttachment(url.path());
+ }
+ }
+}
+
void ComposeWidget::slotRemoveAttachment()
{
m_composer->removeAttachment(ui->attachmentsView->currentIndex());
diff --git a/src/Gui/ComposeWidget.h b/src/Gui/ComposeWidget.h
index 7a9882b..a0368d9 100644
--- a/src/Gui/ComposeWidget.h
+++ b/src/Gui/ComposeWidget.h
@@ -21,6 +21,8 @@
#ifndef COMPOSEWIDGET_H
#define COMPOSEWIDGET_H
+#include <QList>
+#include <QUrl>
#include <QWidget>
#include "Imap/Model/MessageComposer.h"
@@ -73,6 +75,7 @@ private slots:
void slotAskForFileAttachment();
void slotRemoveAttachment();
+ void slotAttachFiles(QList<QUrl> urls);
void slotAppendUidKnown(const uint uidValidity, const uint uid);
void slotGenUrlAuthReceived(const QString &url);
diff --git a/src/Gui/ComposeWidget.ui b/src/Gui/ComposeWidget.ui
index a6690bd..504b48d 100644
--- a/src/Gui/ComposeWidget.ui
+++ b/src/Gui/ComposeWidget.ui
@@ -129,7 +129,7 @@
</widget>
</item>
<item>
- <widget class="QListView" name="attachmentsView">
+ <widget class="ComposerAttachments" name="attachmentsView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
@@ -180,7 +180,7 @@
</layout>
</item>
<item>
- <widget class="QTextEdit" name="mailText">
+ <widget class="ComposerTextEdit" name="mailText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@@ -202,6 +202,18 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>ComposerTextEdit</class>
+ <extends>QTextEdit</extends>
+ <header>ComposerTextEdit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>ComposerAttachments</class>
+ <extends>QListView</extends>
+ <header>ComposerAttachments.h</header>
+ </customwidget>
+ </customwidgets>
<tabstops>
<tabstop>sender</tabstop>
<tabstop>subject</tabstop>
diff --git a/src/Gui/ComposerAttachments.cpp b/src/Gui/ComposerAttachments.cpp
new file mode 100644
index 0000000..0b35c41
--- /dev/null
+++ b/src/Gui/ComposerAttachments.cpp
@@ -0,0 +1,64 @@
+/* Copyright (C) 2012 Thomas Lübking <[email protected]>
+ *
+ * This file is part of the Trojita Qt IMAP e-mail client,
+ * http://trojita.flaska.net/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or the version 3 of the License.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "ComposerAttachments.h"
+#include <QDragEnterEvent>
+#include <QDebug>
+
+ComposerAttachments::ComposerAttachments(QWidget *parent) : QListView(parent), m_dragging(false), m_dragInside(false)
+{
+ setMouseTracking( true );
+ setAcceptDrops(true);
+ setDragDropMode( DragDrop );
+ setDragDropOverwriteMode( false );
+ setDragEnabled(true);
+ setDropIndicatorShown(false);
+}
+
+
+void ComposerAttachments::startDrag(Qt::DropActions da)
+{
+ m_dragging = true;
+ m_dragInside = true;
+ const QModelIndex idx = indexAt(mapFromGlobal(QCursor::pos()));
+ if (!idx.isValid())
+ setCurrentIndex(idx);
+ QListView::startDrag(da);
+ m_dragging = false;
+ if (!m_dragInside) {
+ emit itemDroppedOut();
+ }
+}
+
+
+void ComposerAttachments::dragEnterEvent(QDragEnterEvent *de)
+{
+ if (m_dragging)
+ m_dragInside = true;
+ QListView::dragEnterEvent(de);
+}
+
+void ComposerAttachments::dragLeaveEvent(QDragLeaveEvent *de)
+{
+ if (m_dragging)
+ m_dragInside = false;
+ QListView::dragLeaveEvent(de);
+}
diff --git a/src/Gui/ComposerAttachments.h b/src/Gui/ComposerAttachments.h
new file mode 100644
index 0000000..28e0ea0
--- /dev/null
+++ b/src/Gui/ComposerAttachments.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2012 Thomas Lübking <[email protected]>
+ *
+ * This file is part of the Trojita Qt IMAP e-mail client,
+ * http://trojita.flaska.net/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or the version 3 of the License.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <QList>
+#include <QListView>
+#include <QUrl>
+
+class ComposerAttachments : public QListView {
+ Q_OBJECT
+public:
+ ComposerAttachments(QWidget *parent = 0);
+signals:
+ void itemDroppedOut();
+protected:
+ void startDrag(Qt::DropActions da);
+ void dragEnterEvent(QDragEnterEvent *de);
+ void dragLeaveEvent(QDragLeaveEvent *de);
+private:
+ bool m_dragging, m_dragInside;
+};
\ No newline at end of file
diff --git a/src/Gui/ComposerTextEdit.cpp b/src/Gui/ComposerTextEdit.cpp
new file mode 100644
index 0000000..0a39e80
--- /dev/null
+++ b/src/Gui/ComposerTextEdit.cpp
@@ -0,0 +1,101 @@
+/* Copyright (C) 2012 Thomas Lübking <[email protected]>
+ *
+ * This file is part of the Trojita Qt IMAP e-mail client,
+ * http://trojita.flaska.net/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or the version 3 of the License.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "ComposerTextEdit.h"
+#include <QMimeData>
+#include <QPainter>
+#include <QPaintEvent>
+#include <QTimer>
+#include <QUrl>
+
+ComposerTextEdit::ComposerTextEdit(QWidget *parent) : QTextEdit(parent)
+{
+ m_notificationTimer = new QTimer(this);
+ m_notificationTimer->setSingleShot(true);
+ connect (m_notificationTimer, SIGNAL(timeout()), SLOT(resetNotification()));
+}
+
+void ComposerTextEdit::notify(const QString &n, uint timeout)
+{
+ m_notification = n;
+ if (m_notification.isEmpty() || !timeout) {
+ m_notificationTimer->stop();
+ } else {
+ m_notificationTimer->start(timeout);
+ }
+ viewport()->update();
+}
+
+void ComposerTextEdit::resetNotification()
+{
+ notify(QString());
+}
+
+bool ComposerTextEdit::canInsertFromMimeData( const QMimeData * source ) const
+{
+ QList<QUrl> urls = source->urls();
+ foreach (const QUrl &url, urls) {
+ if (url.isLocalFile())
+ return true;
+ }
+ return QTextEdit::canInsertFromMimeData(source);
+}
+
+void ComposerTextEdit::insertFromMimeData(const QMimeData *source)
+{
+ QList<QUrl> urls = source->urls();
+ foreach (const QUrl &url, urls) {
+ if (url.isLocalFile()) {
+ emit urlsAdded(urls);
+ return;
+ }
+ }
+ QTextEdit::insertFromMimeData(source);
+}
+
+void ComposerTextEdit::paintEvent(QPaintEvent *pe)
+{
+ QTextEdit::paintEvent(pe);
+ if ( !m_notification.isEmpty() )
+ {
+ const int s = width()/5;
+ QRect r(s, 0, width()-2*s, height());
+ QPainter p(viewport());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setClipRegion(pe->region());
+ QFont fnt = font();
+ fnt.setBold(true);
+ fnt.setPointSize( fnt.pointSize()*2*r.width()/(3*QFontMetrics(fnt).width(m_notification)) );
+ r.setHeight( QFontMetrics(fnt).height() + 16 );
+ r.moveCenter( rect().center() );
+
+ QColor c = palette().color(viewport()->foregroundRole());
+ c.setAlpha( 2 * c.alpha() / 3 );
+ p.setBrush( c );
+ p.setPen( Qt::NoPen );
+ p.drawRoundedRect( r, 8,8 );
+
+ p.setPen( palette().color(viewport()->backgroundRole()) );
+ p.setFont( fnt );
+ p.drawText(r, Qt::AlignCenter|Qt::TextDontClip, m_notification );
+ p.end();
+ }
+}
diff --git a/src/Gui/ComposerTextEdit.h b/src/Gui/ComposerTextEdit.h
new file mode 100644
index 0000000..eef4cf9
--- /dev/null
+++ b/src/Gui/ComposerTextEdit.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2012 Thomas Lübking <[email protected]>
+ *
+ * This file is part of the Trojita Qt IMAP e-mail client,
+ * http://trojita.flaska.net/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or the version 3 of the License.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+class QTimer;
+
+#include <QList>
+#include <QUrl>
+#include <QTextEdit>
+
+class ComposerTextEdit : public QTextEdit {
+ Q_OBJECT
+public:
+ ComposerTextEdit(QWidget *parent = 0);
+ /**
+ * use the view to display a notification for @p timeout ms
+ * using an empty or null string will clear the notification at once
+ * a @p timeout of 0ms shows the notification until it's replaced or reset
+ */
+ void notify(const QString &n, uint timeout = 0);
+signals:
+ void urlsAdded(QList<QUrl> urls);
+protected:
+ /** DND reimplementation **/
+ bool canInsertFromMimeData( const QMimeData * source ) const;
+ void insertFromMimeData(const QMimeData *source);
+ /** painter reimplementation for notification **/
+ void paintEvent(QPaintEvent *pe);
+private slots:
+ void resetNotification();
+private:
+ QString m_notification;
+ QTimer *m_notificationTimer;
+};
\ No newline at end of file
diff --git a/src/Gui/Gui.pro b/src/Gui/Gui.pro
index fc94c68..e517052 100644
--- a/src/Gui/Gui.pro
+++ b/src/Gui/Gui.pro
@@ -43,7 +43,9 @@ SOURCES += \
MessageListWidget.cpp \
MailBoxTreeView.cpp \
LocalAddressbook.cpp \
- AbookAddressbook.cpp
+ AbookAddressbook.cpp \
+ ComposerTextEdit.cpp \
+ ComposerAttachments.cpp
HEADERS += \
../Imap/Model/ModelTest/modeltest.h \
ComposeWidget.h \
@@ -73,7 +75,9 @@ HEADERS += \
MailBoxTreeView.h \
AbstractAddressbook.h \
LocalAddressbook.h \
- AbookAddressbook.h
+ AbookAddressbook.h \
+ ComposerTextEdit.h \
+ ComposerAttachments.h
FORMS += CreateMailboxDialog.ui \
ComposeWidget.ui \
SettingsImapPage.ui \
diff --git a/src/Imap/Model/MessageComposer.cpp b/src/Imap/Model/MessageComposer.cpp
index 77df4d4..68a519a 100644
--- a/src/Imap/Model/MessageComposer.cpp
+++ b/src/Imap/Model/MessageComposer.cpp
@@ -23,6 +23,7 @@
#include <QBuffer>
#include <QCoreApplication>
#include <QMimeData>
+#include <QUrl>
#include <QUuid>
#include "Imap/Encoders.h"
#include "Imap/Model/ComposerAttachments.h"
@@ -136,7 +137,15 @@ bool MessageComposer::dropMimeData(const QMimeData *data, Qt::DropAction action,
QDataStream stream(&encodedData, QIODevice::ReadOnly);
return dropImapPart(stream);
} else {
- return false;
+ bool attached = false;
+ QList<QUrl> urls = data->urls();
+ foreach (const QUrl &url, urls) {
+ if (url.isLocalFile()) {
+ addFileAttachment(url.path());
+ attached = true;
+ }
+ }
+ return attached;
}
}
@@ -342,7 +351,8 @@ QStringList MessageComposer::mimeTypes() const
{
return QStringList() << QLatin1String("application/x-trojita-message-list") <<
QLatin1String("application/x-trojita-imap-part") <<
- QLatin1String("application/x-trojita-attachments-list");
+ QLatin1String("application/x-trojita-attachments-list") <<
+ QLatin1String("text/uri-list");
}
void MessageComposer::setFrom(const Message::MailAddress &from)
--
1.7.12.2
From 85bd36acf6dd6c4715552f946bff3a44ee54ce42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <[email protected]>
Date: Wed, 10 Oct 2012 00:31:20 +0200
Subject: [PATCH 2/6] send by ctrl+enter
---
src/Gui/ComposeWidget.cpp | 1 +
src/Gui/ComposerTextEdit.cpp | 8 ++++++++
src/Gui/ComposerTextEdit.h | 2 ++
3 files changed, 11 insertions(+)
diff --git a/src/Gui/ComposeWidget.cpp b/src/Gui/ComposeWidget.cpp
index efdd514..d8ad22e 100644
--- a/src/Gui/ComposeWidget.cpp
+++ b/src/Gui/ComposeWidget.cpp
@@ -95,6 +95,7 @@ ComposeWidget::ComposeWidget(MainWindow *parent) :
ui->mailText->setFont(font);
connect(ui->mailText, SIGNAL(urlsAdded(QList<QUrl>)), SLOT(slotAttachFiles(QList<QUrl>)));
+ connect(ui->mailText, SIGNAL(sendRequest()), SLOT(send()));
}
ComposeWidget::~ComposeWidget()
diff --git a/src/Gui/ComposerTextEdit.cpp b/src/Gui/ComposerTextEdit.cpp
index 0a39e80..5f956e1 100644
--- a/src/Gui/ComposerTextEdit.cpp
+++ b/src/Gui/ComposerTextEdit.cpp
@@ -71,6 +71,14 @@ void ComposerTextEdit::insertFromMimeData(const QMimeData *source)
QTextEdit::insertFromMimeData(source);
}
+void ComposerTextEdit::keyReleaseEvent(QKeyEvent *ke) {
+ if ((ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) && ke->modifiers() == Qt::ControlModifier) {
+ emit sendRequest();
+ return;
+ }
+ QTextEdit::keyReleaseEvent(ke);
+}
+
void ComposerTextEdit::paintEvent(QPaintEvent *pe)
{
QTextEdit::paintEvent(pe);
diff --git a/src/Gui/ComposerTextEdit.h b/src/Gui/ComposerTextEdit.h
index eef4cf9..c347e92 100644
--- a/src/Gui/ComposerTextEdit.h
+++ b/src/Gui/ComposerTextEdit.h
@@ -36,11 +36,13 @@ public:
*/
void notify(const QString &n, uint timeout = 0);
signals:
+ void sendRequest();
void urlsAdded(QList<QUrl> urls);
protected:
/** DND reimplementation **/
bool canInsertFromMimeData( const QMimeData * source ) const;
void insertFromMimeData(const QMimeData *source);
+ void keyReleaseEvent(QKeyEvent *event);
/** painter reimplementation for notification **/
void paintEvent(QPaintEvent *pe);
private slots:
--
1.7.12.2
From 2bf0c52c73d318c904194ddae706b8c25a56b783 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <[email protected]>
Date: Wed, 10 Oct 2012 00:33:33 +0200
Subject: [PATCH 3/6] constrain input, no rich text, 78 chars, wordwrap
---
src/Gui/ComposerTextEdit.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Gui/ComposerTextEdit.cpp b/src/Gui/ComposerTextEdit.cpp
index 5f956e1..580bb6e 100644
--- a/src/Gui/ComposerTextEdit.cpp
+++ b/src/Gui/ComposerTextEdit.cpp
@@ -28,6 +28,10 @@
ComposerTextEdit::ComposerTextEdit(QWidget *parent) : QTextEdit(parent)
{
+ setAcceptRichText(false);
+ setLineWrapMode(QTextEdit::FixedColumnWidth);
+ setWordWrapMode(QTextOption::WordWrap);
+ setLineWrapColumnOrWidth(78);
m_notificationTimer = new QTimer(this);
m_notificationTimer->setSingleShot(true);
connect (m_notificationTimer, SIGNAL(timeout()), SLOT(resetNotification()));
--
1.7.12.2
From 11586a97d3471e4077226620a103297d6241f863 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <[email protected]>
Date: Fri, 12 Oct 2012 22:16:56 +0200
Subject: [PATCH 4/6] auto reset search 250ms after the lineedit is emptied
---
src/Gui/MessageListWidget.cpp | 13 +++++++++++++
src/Gui/MessageListWidget.h | 5 +++++
2 files changed, 18 insertions(+)
diff --git a/src/Gui/MessageListWidget.cpp b/src/Gui/MessageListWidget.cpp
index bea0e78..6d79b97 100644
--- a/src/Gui/MessageListWidget.cpp
+++ b/src/Gui/MessageListWidget.cpp
@@ -21,6 +21,7 @@
#include "MessageListWidget.h"
#include <QLineEdit>
+#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
#include "MsgListView.h"
@@ -41,6 +42,7 @@ MessageListWidget::MessageListWidget(QWidget *parent) :
connect(m_quickSearchText, SIGNAL(returnPressed()), this, SLOT(slotApplySearch()));
connect(m_quickSearchText, SIGNAL(textChanged(QString)), this, SLOT(slotAutoHideOptionsBar()));
+ connect(m_quickSearchText, SIGNAL(textChanged(QString)), this, SLOT(slotConditionalSearchReset()));
m_searchOptionsBar = new QWidget(this);
@@ -87,6 +89,9 @@ MessageListWidget::MessageListWidget(QWidget *parent) :
layout->addWidget(m_searchOptionsBar);
layout->addWidget(tree);
+ m_searchResetTimer = new QTimer(this);
+ connect (m_searchResetTimer, SIGNAL(timeout()), SLOT(slotApplySearch()));
+
slotAutoEnableDisableSearch();
}
@@ -121,6 +126,14 @@ void MessageListWidget::slotAutoHideOptionsBar()
m_searchOptionsBar->setVisible(!m_quickSearchText->text().isEmpty() && m_quickSearchText->isEnabled());
}
+void MessageListWidget::slotConditionalSearchReset()
+{
+ if (m_quickSearchText->text().isEmpty())
+ m_searchResetTimer->start(250);
+ else
+ m_searchResetTimer->stop();
+}
+
QStringList MessageListWidget::searchConditions() const
{
if (!m_quickSearchText->isEnabled() || m_quickSearchText->text().isEmpty())
diff --git a/src/Gui/MessageListWidget.h b/src/Gui/MessageListWidget.h
index 01802d8..b66444f 100644
--- a/src/Gui/MessageListWidget.h
+++ b/src/Gui/MessageListWidget.h
@@ -25,6 +25,7 @@
#include <QWidget>
class QLineEdit;
+class QTimer;
class QToolButton;
namespace Gui {
@@ -53,6 +54,9 @@ protected slots:
void slotAutoEnableDisableSearch();
void slotAutoHideOptionsBar();
+private slots:
+ void slotConditionalSearchReset();
+
private:
QLineEdit *m_quickSearchText;
QWidget *m_searchOptionsBar;
@@ -62,6 +66,7 @@ private:
QToolButton *m_searchInRecipients;
QToolButton *m_searchFuzzy;
bool m_supportsFuzzySearch;
+ QTimer *m_searchResetTimer;
};
}
--
1.7.12.2
From 8556be10f4467e01838a86cee819a72e3d922ba7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <[email protected]>
Date: Fri, 12 Oct 2012 22:22:51 +0200
Subject: [PATCH 5/6] new take search gui, introduce complex imap query
builder
---
src/Gui/MessageListWidget.cpp | 150 +++++++++++++++++++++++++++++-------------
src/Gui/MessageListWidget.h | 17 +++--
2 files changed, 113 insertions(+), 54 deletions(-)
diff --git a/src/Gui/MessageListWidget.cpp b/src/Gui/MessageListWidget.cpp
index 6d79b97..05fee14 100644
--- a/src/Gui/MessageListWidget.cpp
+++ b/src/Gui/MessageListWidget.cpp
@@ -20,14 +20,18 @@
*/
#include "MessageListWidget.h"
+#include <QAction>
+#include <QCheckBox>
+#include <QFrame>
#include <QLineEdit>
+#include <QMenu>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
+#include <QWidgetAction>
+#include "IconLoader.h"
#include "MsgListView.h"
-#include <QDebug>
-
namespace Gui {
MessageListWidget::MessageListWidget(QWidget *parent) :
@@ -39,54 +43,61 @@ MessageListWidget::MessageListWidget(QWidget *parent) :
#if QT_VERSION >= 0x040700
m_quickSearchText->setPlaceholderText(tr("Quick Search / Leading \":=\" for direct IMAP search"));
#endif
+ m_queryPlaceholder = tr("<query>");
connect(m_quickSearchText, SIGNAL(returnPressed()), this, SLOT(slotApplySearch()));
- connect(m_quickSearchText, SIGNAL(textChanged(QString)), this, SLOT(slotAutoHideOptionsBar()));
connect(m_quickSearchText, SIGNAL(textChanged(QString)), this, SLOT(slotConditionalSearchReset()));
-
- m_searchOptionsBar = new QWidget(this);
-
- // The option bar shall use a slightly smaller font size
- QFont f = font();
- f.setPointSizeF(f.pointSizeF() * 0.80);
- m_searchOptionsBar->setFont(f);
-
- m_searchFuzzy = new QToolButton(m_searchOptionsBar);
- m_searchFuzzy->setText(tr("Fuzzy Search"));
- m_searchFuzzy->setAutoRaise(true);
+ connect(m_quickSearchText, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(slotUpdateSearchCursor()));
+
+ m_searchOptions = new QToolButton(this);
+ m_searchOptions->setPopupMode(QToolButton::InstantPopup);
+ m_searchOptions->setText("*");
+ m_searchOptions->setIcon(loadIcon(QLatin1String("configure")));
+ QMenu *optionsMenu = new QMenu(m_searchOptions);
+ m_searchFuzzy = optionsMenu->addAction(tr("Fuzzy Search"));
m_searchFuzzy->setCheckable(true);
- m_searchInSubject = new QToolButton(m_searchOptionsBar);
- m_searchInSubject->setText(tr("Subject"));
- m_searchInSubject->setAutoRaise(true);
+ optionsMenu->addSeparator();
+ m_searchInSubject = optionsMenu->addAction(tr("Subject"));
m_searchInSubject->setCheckable(true);
m_searchInSubject->setChecked(true);
- m_searchInBody = new QToolButton(m_searchOptionsBar);
- m_searchInBody->setText(tr("Body"));
- m_searchInBody->setAutoRaise(true);
+ m_searchInBody = optionsMenu->addAction(tr("Body"));
m_searchInBody->setCheckable(true);
- m_searchInSenders = new QToolButton(m_searchOptionsBar);
- m_searchInSenders->setText(tr("Senders"));
- m_searchInSenders->setAutoRaise(true);
+ m_searchInSenders = optionsMenu->addAction(tr("Senders"));
m_searchInSenders->setCheckable(true);
m_searchInSenders->setChecked(true);
- m_searchInRecipients = new QToolButton(m_searchOptionsBar);
- m_searchInRecipients->setText(tr("Recipients"));
- m_searchInRecipients->setAutoRaise(true);
+ m_searchInRecipients = optionsMenu->addAction(tr("Recipients"));
m_searchInRecipients->setCheckable(true);
- QHBoxLayout *fieldsLayout = new QHBoxLayout(m_searchOptionsBar);
- fieldsLayout->setSpacing(0);
- fieldsLayout->addWidget(m_searchFuzzy);
- fieldsLayout->addStretch();
- fieldsLayout->addWidget(m_searchInSubject);
- fieldsLayout->addWidget(m_searchInBody);
- fieldsLayout->addWidget(m_searchInSenders);
- fieldsLayout->addWidget(m_searchInRecipients);
+ optionsMenu->addSeparator();
+
+ QMenu *complexMenu = new QMenu(tr("Complex IMAP query"), optionsMenu);
+ connect(complexMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotComplexSearchInput(QAction*)));
+ complexMenu->addAction(tr("Not ..."))->setData("NOT " + m_queryPlaceholder);
+ complexMenu->addAction(tr("Either... or..."))->setData("OR " + m_queryPlaceholder + " " + m_queryPlaceholder);
+ complexMenu->addSeparator();
+ complexMenu->addAction(tr("From sender"))->setData("FROM " + m_queryPlaceholder);
+ complexMenu->addAction(tr("To receiver"))->setData("TO " + m_queryPlaceholder);
+ complexMenu->addSeparator();
+ complexMenu->addAction(tr("About subject"))->setData("SUBJECT " + m_queryPlaceholder);
+ complexMenu->addAction(tr("Message contains ..."))->setData("BODY " + m_queryPlaceholder);
+ complexMenu->addSeparator();
+ complexMenu->addAction(tr("Before date"))->setData("BEFORE <d-mmm-yyyy>");
+ complexMenu->addAction(tr("Since date"))->setData("SINCE <d-mmm-yyyy>");
+ complexMenu->addSeparator();
+ complexMenu->addAction(tr("Has been seen"))->setData("SEEN");
+
+ optionsMenu->addMenu(complexMenu);
+
+ m_searchOptions->setMenu(optionsMenu);
+ connect (optionsMenu, SIGNAL(aboutToShow()), SLOT(slotDeActivateSimpleSearch()));
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->addWidget(m_searchOptions);
+ hlayout->addWidget(m_quickSearchText);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setSpacing(0);
- layout->addWidget(m_quickSearchText);
- layout->addWidget(m_searchOptionsBar);
+ layout->addLayout(hlayout);
layout->addWidget(tree);
m_searchResetTimer = new QTimer(this);
@@ -113,17 +124,7 @@ void MessageListWidget::slotAutoEnableDisableSearch()
isEnabled = false;
}
m_quickSearchText->setEnabled(isEnabled);
- m_searchFuzzy->setEnabled(isEnabled && m_supportsFuzzySearch);
- m_searchInBody->setEnabled(isEnabled);
- m_searchInRecipients->setEnabled(isEnabled);
- m_searchInSenders->setEnabled(isEnabled);
- m_searchInSubject->setEnabled(isEnabled);
- slotAutoHideOptionsBar();
-}
-
-void MessageListWidget::slotAutoHideOptionsBar()
-{
- m_searchOptionsBar->setVisible(!m_quickSearchText->text().isEmpty() && m_quickSearchText->isEnabled());
+ m_searchOptions->setEnabled(isEnabled);
}
void MessageListWidget::slotConditionalSearchReset()
@@ -134,6 +135,61 @@ void MessageListWidget::slotConditionalSearchReset()
m_searchResetTimer->stop();
}
+void MessageListWidget::slotUpdateSearchCursor()
+{
+ int cp = m_quickSearchText->cursorPosition();
+ int ts = -1, te = -1;
+ for (int i = cp-1; i > -1; --i) {
+ if (m_quickSearchText->text().at(i) == '>')
+ break; // invalid
+ if (m_quickSearchText->text().at(i) == '<') {
+ ts = i;
+ break; // found TagStart
+ }
+ }
+ if (ts < 0)
+ return; // not inside tag!
+ for (int i = cp; i < m_quickSearchText->text().length(); ++i) {
+ if (m_quickSearchText->text().at(i) == '<')
+ break; // invalid
+ if (m_quickSearchText->text().at(i) == '>') {
+ te = i;
+ break; // found TagEnd
+ }
+ }
+ if (te < 0)
+ return; // not inside tag?
+ if (m_quickSearchText->text().midRef(ts, m_queryPlaceholder.length()) == m_queryPlaceholder)
+ m_quickSearchText->setSelection(ts, m_queryPlaceholder.length());
+}
+
+void MessageListWidget::slotComplexSearchInput(QAction *act)
+{
+ QString s = act->data().toString();
+ const int selectionStart = m_quickSearchText->selectionStart() - 1;
+ if (selectionStart > -1 && m_quickSearchText->text().at(selectionStart) != ' ')
+ s.prepend(' ');
+ m_quickSearchText->insert(s);
+ if (!m_quickSearchText->text().startsWith(":=")) {
+ s = m_quickSearchText->text().trimmed();
+ m_quickSearchText->setText(":=" + s);
+ }
+ m_quickSearchText->setFocus();
+ const int pos = m_quickSearchText->text().indexOf(m_queryPlaceholder);
+ if (pos > -1)
+ m_quickSearchText->setSelection(pos, m_queryPlaceholder.length());
+}
+
+void MessageListWidget::slotDeActivateSimpleSearch()
+{
+ const bool isEnabled = !m_quickSearchText->text().startsWith(":=");
+ m_searchInSubject->setEnabled(isEnabled);
+ m_searchInBody->setEnabled(isEnabled);
+ m_searchInSenders->setEnabled(isEnabled);
+ m_searchInRecipients->setEnabled(isEnabled);
+ m_searchFuzzy->setEnabled(isEnabled && m_supportsFuzzySearch);
+}
+
QStringList MessageListWidget::searchConditions() const
{
if (!m_quickSearchText->isEnabled() || m_quickSearchText->text().isEmpty())
diff --git a/src/Gui/MessageListWidget.h b/src/Gui/MessageListWidget.h
index b66444f..e1ebaa2 100644
--- a/src/Gui/MessageListWidget.h
+++ b/src/Gui/MessageListWidget.h
@@ -52,21 +52,24 @@ signals:
protected slots:
void slotApplySearch();
void slotAutoEnableDisableSearch();
- void slotAutoHideOptionsBar();
private slots:
+ void slotComplexSearchInput(QAction*);
void slotConditionalSearchReset();
+ void slotDeActivateSimpleSearch();
+ void slotUpdateSearchCursor();
private:
QLineEdit *m_quickSearchText;
- QWidget *m_searchOptionsBar;
- QToolButton *m_searchInSubject;
- QToolButton *m_searchInBody;
- QToolButton *m_searchInSenders;
- QToolButton *m_searchInRecipients;
- QToolButton *m_searchFuzzy;
+ QToolButton *m_searchOptions;
+ QAction *m_searchInSubject;
+ QAction *m_searchInBody;
+ QAction *m_searchInSenders;
+ QAction *m_searchInRecipients;
+ QAction *m_searchFuzzy;
bool m_supportsFuzzySearch;
QTimer *m_searchResetTimer;
+ QString m_queryPlaceholder;
};
}
--
1.7.12.2