• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kmail

  • sources
  • kde-4.14
  • kdepim
  • kmail
  • tag
tagactionmanager.cpp
Go to the documentation of this file.
1 /* Copyright 2010 Thomas McGuire <mcguire@kde.org>
2  Copyright 2011-2015 Laurent Montel <montel@kde.org>
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License as
6  published by the Free Software Foundation; either version 2 of
7  the License or (at your option) version 3 or any later version
8  accepted by the membership of KDE e.V. (or its successor approved
9  by the membership of KDE e.V.), which shall act as a proxy
10  defined in Section 14 of version 3 of the license.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #include "tagactionmanager.h"
21 
22 #include "messageactions.h"
23 
24 #include "mailcommon/tag/addtagdialog.h"
25 
26 #include <KAction>
27 #include <KActionCollection>
28 #include <KToggleAction>
29 #include <KXMLGUIClient>
30 #include <KActionMenu>
31 #include <KMenu>
32 #include <KLocalizedString>
33 #include <KJob>
34 #include <Akonadi/Monitor>
35 
36 #include <QSignalMapper>
37 #include <QPointer>
38 
39 #include <Akonadi/TagFetchJob>
40 #include <Akonadi/TagFetchScope>
41 #include <Akonadi/TagAttribute>
42 
43 using namespace KMail;
44 
45 static int s_numberMaxTag = 10;
46 
47 TagActionManager::TagActionManager( QObject *parent, KActionCollection *actionCollection,
48  MessageActions *messageActions, KXMLGUIClient *guiClient )
49  : QObject( parent ),
50  mActionCollection( actionCollection ),
51  mMessageActions( messageActions ),
52  mMessageTagToggleMapper( 0 ),
53  mGUIClient( guiClient ),
54  mSeparatorMoreAction( 0 ),
55  mSeparatorNewTagAction( 0 ),
56  mMoreAction( 0 ),
57  mNewTagAction( 0 ),
58  mNewTagId(-1),
59  mTagFetchInProgress( false ),
60  mMonitor(new Akonadi::Monitor(this))
61 {
62  mMessageActions->messageStatusMenu()->menu()->addSeparator();
63 
64  mMonitor->setTypeMonitored(Akonadi::Monitor::Tags);
65  mMonitor->tagFetchScope().fetchAttribute<Akonadi::TagAttribute>();
66  connect(mMonitor, SIGNAL(tagAdded(Akonadi::Tag)), this, SLOT(onTagAdded(Akonadi::Tag)));
67  connect(mMonitor, SIGNAL(tagRemoved(Akonadi::Tag)), this, SLOT(onTagRemoved(Akonadi::Tag)));
68  connect(mMonitor, SIGNAL(tagChanged(Akonadi::Tag)), this, SLOT(onTagChanged(Akonadi::Tag)));
69 }
70 
71 TagActionManager::~TagActionManager()
72 {
73 }
74 
75 void TagActionManager::clearActions()
76 {
77  //Remove the tag actions from the toolbar
78  if ( !mToolbarActions.isEmpty() ) {
79  if ( mGUIClient->factory() ) {
80  mGUIClient->unplugActionList( QLatin1String("toolbar_messagetag_actions") );
81  }
82  mToolbarActions.clear();
83  }
84 
85  //Remove the tag actions from the status menu and the action collection,
86  //then delete them.
87  foreach( KAction *action, mTagActions ) {
88  mMessageActions->messageStatusMenu()->removeAction( action );
89 
90  // This removes and deletes the action at the same time
91  mActionCollection->removeAction( action );
92  }
93 
94  if ( mSeparatorMoreAction ) {
95  mMessageActions->messageStatusMenu()->removeAction( mSeparatorMoreAction );
96  }
97 
98  if ( mSeparatorNewTagAction ) {
99  mMessageActions->messageStatusMenu()->removeAction( mSeparatorNewTagAction );
100  }
101 
102  if ( mNewTagAction ) {
103  mMessageActions->messageStatusMenu()->removeAction( mNewTagAction );
104  }
105 
106  if ( mMoreAction ) {
107  mMessageActions->messageStatusMenu()->removeAction( mMoreAction );
108  }
109 
110 
111  mTagActions.clear();
112  delete mMessageTagToggleMapper;
113  mMessageTagToggleMapper = 0;
114 }
115 
116 void TagActionManager::createTagAction( const MailCommon::Tag::Ptr &tag, bool addToMenu )
117 {
118  QString cleanName( i18n("Message Tag: %1", tag->tagName ) );
119  cleanName.replace(QLatin1Char('&'), QLatin1String("&&"));
120  KToggleAction * const tagAction = new KToggleAction( KIcon( tag->iconName ),
121  cleanName, this );
122  tagAction->setShortcut( tag->shortcut );
123  tagAction->setIconText( tag->name() );
124  tagAction->setChecked( tag->id() == mNewTagId );
125 
126  mActionCollection->addAction( tag->name(), tagAction );
127  connect( tagAction, SIGNAL(triggered(bool)),
128  mMessageTagToggleMapper, SLOT(map()) );
129 
130  // The shortcut configuration is done in the config dialog.
131  // The shortcut set in the shortcut dialog would not be saved back to
132  // the tag descriptions correctly.
133  tagAction->setShortcutConfigurable( false );
134  mMessageTagToggleMapper->setMapping( tagAction, QString::number(tag->tag().id()) );
135 
136  mTagActions.insert( tag->id(), tagAction );
137  if ( addToMenu )
138  mMessageActions->messageStatusMenu()->menu()->addAction( tagAction );
139 
140  if ( tag->inToolbar ) {
141  mToolbarActions.append( tagAction );
142  }
143 }
144 
145 void TagActionManager::createActions()
146 {
147  if ( mTagFetchInProgress )
148  return;
149 
150  if ( mTags.isEmpty() ) {
151  mTagFetchInProgress = true;
152  Akonadi::TagFetchJob *fetchJob = new Akonadi::TagFetchJob(this);
153  fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>();
154  connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(finishedTagListing(KJob*)));
155  } else {
156  mTagFetchInProgress = false;
157  createTagActions(mTags);
158  }
159 }
160 
161 void TagActionManager::finishedTagListing(KJob *job)
162 {
163  if (job->error()) {
164  kWarning() << job->errorString();
165  }
166  Akonadi::TagFetchJob *fetchJob = static_cast<Akonadi::TagFetchJob*>(job);
167  foreach (const Akonadi::Tag &result, fetchJob->tags()) {
168  mTags.append( MailCommon::Tag::fromAkonadi( result ) );
169  }
170  mTagFetchInProgress = false;
171  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
172  createTagActions(mTags);
173 }
174 
175 void TagActionManager::onSignalMapped(const QString& tag)
176 {
177  emit tagActionTriggered( Akonadi::Tag( tag.toLongLong() ) );
178 }
179 
180 void TagActionManager::createTagActions(const QList<MailCommon::Tag::Ptr> &tags)
181 {
182  clearActions();
183  //Use a mapper to understand which tag button is triggered
184  mMessageTagToggleMapper = new QSignalMapper( this );
185  connect( mMessageTagToggleMapper, SIGNAL(mapped(QString)),
186  this, SLOT(onSignalMapped(QString)) );
187 
188  // Create a action for each tag and plug it into various places
189  int i = 0;
190  bool needToAddMoreAction = false;
191  const int numberOfTag(tags.size());
192  //It is assumed the tags are sorted
193  foreach( const MailCommon::Tag::Ptr &tag, tags ) {
194  if ( i< s_numberMaxTag )
195  createTagAction( tag,true );
196  else
197  {
198  if ( tag->inToolbar || !tag->shortcut.isEmpty() ) {
199  createTagAction( tag, false );
200  }
201 
202  if ( i == s_numberMaxTag && i < numberOfTag )
203  {
204  needToAddMoreAction = true;
205  }
206  }
207  ++i;
208  }
209 
210 
211  if(!mSeparatorNewTagAction) {
212  mSeparatorNewTagAction = new QAction( this );
213  mSeparatorNewTagAction->setSeparator( true );
214  }
215  mMessageActions->messageStatusMenu()->menu()->addAction( mSeparatorNewTagAction );
216 
217  if (!mNewTagAction) {
218  mNewTagAction = new KAction( i18n( "Add new tag..." ), this );
219  connect( mNewTagAction, SIGNAL(triggered(bool)),
220  this, SLOT(newTagActionClicked()) );
221  }
222  mMessageActions->messageStatusMenu()->menu()->addAction( mNewTagAction );
223 
224  if (needToAddMoreAction) {
225  if(!mSeparatorMoreAction) {
226  mSeparatorMoreAction = new QAction( this );
227  mSeparatorMoreAction->setSeparator( true );
228  }
229  mMessageActions->messageStatusMenu()->menu()->addAction( mSeparatorMoreAction );
230 
231  if (!mMoreAction) {
232  mMoreAction = new KAction( i18n( "More..." ), this );
233  connect( mMoreAction, SIGNAL(triggered(bool)),
234  this, SIGNAL(tagMoreActionClicked()) );
235  }
236  mMessageActions->messageStatusMenu()->menu()->addAction( mMoreAction );
237  }
238 
239  if ( !mToolbarActions.isEmpty() && mGUIClient->factory() ) {
240  mGUIClient->plugActionList( QLatin1String("toolbar_messagetag_actions"), mToolbarActions );
241  }
242 }
243 
244 void TagActionManager::updateActionStates( int numberOfSelectedMessages,
245  const Akonadi::Item &selectedItem )
246 {
247  mNewTagId = -1;
248  QMap<qint64,KToggleAction*>::const_iterator it = mTagActions.constBegin();
249  QMap<qint64,KToggleAction*>::const_iterator end = mTagActions.constEnd();
250  if ( numberOfSelectedMessages >= 1 ) {
251  Q_ASSERT( selectedItem.isValid() );
252  for ( ; it != end; ++it ) {
253  //FIXME Not very performant tag label retrieval
254  QString label(QLatin1String("not found"));
255  foreach (const MailCommon::Tag::Ptr &tag, mTags) {
256  if (tag->id() == it.key()) {
257  label = tag->name();
258  break;
259  }
260  }
261 
262  it.value()->setEnabled( true );
263  if (numberOfSelectedMessages == 1) {
264  const bool hasTag = selectedItem.hasTag(Akonadi::Tag(it.key()));
265  it.value()->setChecked( hasTag );
266  it.value()->setText( i18n("Message Tag: %1", label ) );
267  } else {
268  it.value()->setChecked( false );
269  it.value()->setText( i18n("Toggle Message Tag: %1", label ) );
270  }
271  }
272  } else {
273  for ( ; it != end; ++it ) {
274  it.value()->setEnabled( false );
275  }
276  }
277 }
278 
279 void TagActionManager::onTagAdded(const Akonadi::Tag &akonadiTag)
280 {
281  const QList<qint64> checked = checkedTags();
282 
283  clearActions();
284  mTags.append( MailCommon::Tag::fromAkonadi( akonadiTag ) );
285  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
286  createTagActions(mTags);
287 
288  checkTags( checked );
289 }
290 
291 void TagActionManager::onTagRemoved(const Akonadi::Tag &akonadiTag)
292 {
293  foreach( const MailCommon::Tag::Ptr &tag, mTags ) {
294  if(tag->id() == akonadiTag.id()) {
295  mTags.removeAll(tag);
296  break;
297  }
298  }
299 
300  fillTagList();
301 }
302 
303 void TagActionManager::onTagChanged(const Akonadi::Tag& akonadiTag)
304 {
305  foreach( const MailCommon::Tag::Ptr &tag, mTags ) {
306  if(tag->id() == akonadiTag.id()) {
307  mTags.removeAll(tag);
308  break;
309  }
310  }
311  mTags.append( MailCommon::Tag::fromAkonadi( akonadiTag ) );
312  fillTagList();
313 }
314 
315 void TagActionManager::fillTagList()
316 {
317  const QList<qint64> checked = checkedTags();
318 
319  clearActions();
320  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
321  createTagActions( mTags );
322 
323  checkTags( checked );
324 }
325 
326 void TagActionManager::newTagActionClicked()
327 {
328  QPointer<MailCommon::AddTagDialog> dialog = new MailCommon::AddTagDialog(QList<KActionCollection*>() << mActionCollection, 0);
329  dialog->setTags(mTags);
330  if ( dialog->exec() == QDialog::Accepted ) {
331  mNewTagId = dialog->tag().id();
332  // Assign tag to all selected items right away
333  emit tagActionTriggered( dialog->tag() );
334  }
335  delete dialog;
336 }
337 
338 void TagActionManager::checkTags(const QList<qint64>& tags)
339 {
340  foreach( const qint64 &id, tags ) {
341  if ( mTagActions.contains(id) ) {
342  mTagActions[id]->setChecked( true );
343  }
344  }
345 }
346 
347 QList<qint64> TagActionManager::checkedTags() const
348 {
349  QMap<qint64,KToggleAction*>::const_iterator it = mTagActions.constBegin();
350  QMap<qint64,KToggleAction*>::const_iterator end = mTagActions.constEnd();
351  QList<qint64> checked;
352  for ( ; it != end; ++it ) {
353  if ( it.value()->isChecked() ) {
354  checked << it.key();
355  }
356  }
357  return checked;
358 }
QList::clear
void clear()
QMap::contains
bool contains(const Key &key) const
QAction::setSeparator
void setSeparator(bool b)
KXMLGUIClient
tagactionmanager.h
KMail::TagActionManager::~TagActionManager
~TagActionManager()
Definition: tagactionmanager.cpp:71
QMap::constBegin
const_iterator constBegin() const
QMap
Definition: kmmainwidget.h:66
KMail::TagActionManager::tagActionTriggered
void tagActionTriggered(const Akonadi::Tag &tag)
Emitted when one of the tagging actions was triggered.
KMail::MessageActions
Manages common actions that can be performed on one or more messages.
Definition: messageactions.h:50
QPointer
KMail::TagActionManager::tagMoreActionClicked
void tagMoreActionClicked()
Emitted when we want to select more action.
QMap::clear
void clear()
QList::size
int size() const
messageactions.h
QSignalMapper::setMapping
void setMapping(QObject *sender, int id)
s_numberMaxTag
static int s_numberMaxTag
Definition: tagactionmanager.cpp:45
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
KMail::TagActionManager::clearActions
void clearActions()
Removes all actions from the GUI again.
Definition: tagactionmanager.cpp:75
QObject
QList::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
QMap::constEnd
const_iterator constEnd() const
QString
QList< MailCommon::Tag::Ptr >
QList::end
iterator end()
QLatin1Char
QLatin1String
QAction
KMail::TagActionManager::updateActionStates
void updateActionStates(int numberOfSelectedMessages, const Akonadi::Item &selectedItem)
Updates the state of the toggle actions of all tags.
Definition: tagactionmanager.cpp:244
QMap::insert
iterator insert(const Key &key, const T &value)
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KMail::TagActionManager::createActions
void createActions()
Creates and plugs all tag actions.
Definition: tagactionmanager.cpp:145
KJob
QSignalMapper
QString::toLongLong
qlonglong toLongLong(bool *ok, int base) const
QList::begin
iterator begin()
QtConcurrent::mapped
QFuture< T > mapped(const Sequence &sequence, MapFunction function)
KMail::TagActionManager::TagActionManager
TagActionManager(QObject *parent, KActionCollection *actionCollection, MessageActions *messageActions, KXMLGUIClient *guiClient)
Does not take ownership of the action collection, the GUI client or the message actions.
Definition: tagactionmanager.cpp:47
KMail::MessageActions::messageStatusMenu
KActionMenu * messageStatusMenu() const
Definition: messageactions.h:79
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:33 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal