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

kmail

  • sources
  • kde-4.12
  • kdepim
  • kmail
  • tag
tagactionmanager.cpp
Go to the documentation of this file.
1 /* Copyright 2010 Thomas McGuire <mcguire@kde.org>
2  Copyright 2011-2012-2013 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 #include "messagecore/nepomukutil/asyncnepomukresourceretriever.h"
24 
25 #include "mailcommon/tag/addtagdialog.h"
26 
27 #include <Nepomuk2/Tag>
28 #include <Nepomuk2/ResourceManager>
29 #include <Nepomuk2/Query/QueryServiceClient>
30 #include <Nepomuk2/Query/Result>
31 #include <Nepomuk2/Query/ResourceTypeTerm>
32 
33 #include <KAction>
34 #include <KActionCollection>
35 #include <KActionMenu>
36 #include <KMenu>
37 #include <KToggleAction>
38 #include <KXMLGUIClient>
39 #include <KMessageBox>
40 #include <KDialog>
41 #include <KLineEdit>
42 
43 #include <QSignalMapper>
44 #include <QPointer>
45 #include <soprano/nao.h>
46 #include <nepomuk2/resourcewatcher.h>
47 
48 using namespace KMail;
49 
50 static int s_numberMaxTag = 10;
51 
52 TagActionManager::TagActionManager( QObject *parent, KActionCollection *actionCollection,
53  MessageActions *messageActions, KXMLGUIClient *guiClient )
54  : QObject( parent ),
55  mActionCollection( actionCollection ),
56  mMessageActions( messageActions ),
57  mMessageTagToggleMapper( 0 ),
58  mGUIClient( guiClient ),
59  mSeparatorMoreAction( 0 ),
60  mSeparatorNewTagAction( 0 ),
61  mMoreAction( 0 ),
62  mNewTagAction( 0 ),
63  mTagQueryClient( 0 )
64 {
65  mMessageActions->messageStatusMenu()->menu()->addSeparator();
66  connect( Nepomuk2::ResourceManager::instance(), SIGNAL(nepomukSystemStarted()),
67  SLOT(tagsChanged()) );
68  connect( Nepomuk2::ResourceManager::instance(), SIGNAL(nepomukSystemStopped()),
69  SLOT(tagsChanged()) );
70 
71  Nepomuk2::ResourceWatcher* watcher = new Nepomuk2::ResourceWatcher(this);
72  watcher->addType(Soprano::Vocabulary::NAO::Tag());
73  connect(watcher, SIGNAL(resourceCreated(Nepomuk2::Resource,QList<QUrl>)), this, SLOT(resourceCreated(Nepomuk2::Resource,QList<QUrl>)));
74  connect(watcher, SIGNAL(resourceRemoved(QUrl,QList<QUrl>)),this, SLOT(resourceRemoved(QUrl,QList<QUrl>)));
75  connect(watcher, SIGNAL(propertyChanged(Nepomuk2::Resource,Nepomuk2::Types::Property,QVariantList,QVariantList)),this,SLOT(propertyChanged(Nepomuk2::Resource)));
76  watcher->start();
77 
78  QVector<QUrl> properties;
79  properties << Soprano::Vocabulary::NAO::hasTag();
80 
81  mAsyncNepomukRetriver = new MessageCore::AsyncNepomukResourceRetriever(properties, this);
82  connect(mAsyncNepomukRetriver, SIGNAL(resourceReceived(QUrl,Nepomuk2::Resource)),
83  this, SLOT(slotLoadedResourceForUpdateActionStates(QUrl,Nepomuk2::Resource)));
84 }
85 
86 TagActionManager::~TagActionManager()
87 {
88 }
89 
90 void TagActionManager::clearActions()
91 {
92  //Remove the tag actions from the toolbar
93  if ( !mToolbarActions.isEmpty() ) {
94  if ( mGUIClient->factory() ) {
95  mGUIClient->unplugActionList( QLatin1String("toolbar_messagetag_actions") );
96  }
97  mToolbarActions.clear();
98  }
99 
100  //Remove the tag actions from the status menu and the action collection,
101  //then delete them.
102  foreach( KAction *action, mTagActions ) {
103  mMessageActions->messageStatusMenu()->removeAction( action );
104 
105  // This removes and deletes the action at the same time
106  mActionCollection->removeAction( action );
107  }
108 
109  if ( mSeparatorMoreAction ) {
110  mMessageActions->messageStatusMenu()->removeAction( mSeparatorMoreAction );
111  }
112 
113  if ( mSeparatorNewTagAction ) {
114  mMessageActions->messageStatusMenu()->removeAction( mSeparatorNewTagAction );
115  }
116 
117  if ( mNewTagAction ) {
118  mMessageActions->messageStatusMenu()->removeAction( mNewTagAction );
119  }
120 
121  if ( mMoreAction ) {
122  mMessageActions->messageStatusMenu()->removeAction( mMoreAction );
123  }
124 
125 
126  mTagActions.clear();
127  delete mMessageTagToggleMapper;
128  mMessageTagToggleMapper = 0;
129 }
130 
131 void TagActionManager::createTagAction( const MailCommon::Tag::Ptr &tag, bool addToMenu )
132 {
133  QString cleanName( i18n("Message Tag %1", tag->tagName ) );
134  cleanName.replace(QLatin1Char('&'), QLatin1String("&&"));
135  KToggleAction * const tagAction = new KToggleAction( KIcon( tag->iconName ),
136  cleanName, this );
137  tagAction->setShortcut( tag->shortcut );
138  tagAction->setIconText( tag->tagName );
139  tagAction->setChecked( tag->nepomukResourceUri == mNewTagUri );
140 
141  mActionCollection->addAction( tag->nepomukResourceUri.toString(), tagAction );
142  connect( tagAction, SIGNAL(triggered(bool)),
143  mMessageTagToggleMapper, SLOT(map()) );
144 
145  // The shortcut configuration is done in the config dialog.
146  // The shortcut set in the shortcut dialog would not be saved back to
147  // the tag descriptions correctly.
148  tagAction->setShortcutConfigurable( false );
149  mMessageTagToggleMapper->setMapping( tagAction, tag->nepomukResourceUri.toString() );
150 
151  mTagActions.insert( tag->nepomukResourceUri.toString(), tagAction );
152  if ( addToMenu )
153  mMessageActions->messageStatusMenu()->menu()->addAction( tagAction );
154 
155  if ( tag->inToolbar ) {
156  mToolbarActions.append( tagAction );
157  }
158 }
159 
160 void TagActionManager::createActions()
161 {
162  if( mTagQueryClient )
163  return;
164  clearActions();
165 
166  if ( mTags.isEmpty() ) {
167  mTagQueryClient = new Nepomuk2::Query::QueryServiceClient(this);
168  connect( mTagQueryClient, SIGNAL(newEntries(QList<Nepomuk2::Query::Result>)),
169  this, SLOT(newTagEntries(QList<Nepomuk2::Query::Result>)) );
170  connect( mTagQueryClient, SIGNAL(finishedListing()),
171  this, SLOT(finishedTagListing()) );
172  Nepomuk2::Query::ResourceTypeTerm term( Soprano::Vocabulary::NAO::Tag() );
173  Nepomuk2::Query::Query query( term );
174  mTagQueryClient->query(query);
175  } else {
176  createTagActions();
177  }
178 }
179 
180 void TagActionManager::createTagActions()
181 {
182  //Use a mapper to understand which tag button is triggered
183  mMessageTagToggleMapper = new QSignalMapper( this );
184  connect( mMessageTagToggleMapper, SIGNAL(mapped(QString)),
185  this, SIGNAL(tagActionTriggered(QString)) );
186 
187  // Create a action for each tag and plug it into various places
188  int i = 0;
189  bool needToAddMoreAction = false;
190  const int numberOfTag(mTags.count());
191  foreach( const MailCommon::Tag::Ptr &tag, mTags ) {
192  if(tag->tagStatus)
193  continue;
194  if ( tag->nepomukResourceUri.toString().isEmpty() )
195  continue;
196  if ( i< s_numberMaxTag )
197  createTagAction( tag,true );
198  else
199  {
200  if ( tag->inToolbar || !tag->shortcut.isEmpty() ) {
201  createTagAction( tag, false );
202  }
203 
204  if ( i == s_numberMaxTag && i < numberOfTag )
205  {
206  needToAddMoreAction = true;
207  }
208  }
209  ++i;
210  }
211 
212 
213  if(!mSeparatorNewTagAction) {
214  mSeparatorNewTagAction = new QAction( this );
215  mSeparatorNewTagAction->setSeparator( true );
216  }
217  mMessageActions->messageStatusMenu()->menu()->addAction( mSeparatorNewTagAction );
218 
219  if (!mNewTagAction) {
220  mNewTagAction = new KAction( i18n( "Add new tag..." ), this );
221  connect( mNewTagAction, SIGNAL(triggered(bool)),
222  this, SLOT(newTagActionClicked()) );
223  }
224  mMessageActions->messageStatusMenu()->menu()->addAction( mNewTagAction );
225 
226  if (needToAddMoreAction) {
227  if(!mSeparatorMoreAction) {
228  mSeparatorMoreAction = new QAction( this );
229  mSeparatorMoreAction->setSeparator( true );
230  }
231  mMessageActions->messageStatusMenu()->menu()->addAction( mSeparatorMoreAction );
232 
233  if (!mMoreAction) {
234  mMoreAction = new KAction( i18n( "More..." ), this );
235  connect( mMoreAction, SIGNAL(triggered(bool)),
236  this, SIGNAL(tagMoreActionClicked()) );
237  }
238  mMessageActions->messageStatusMenu()->menu()->addAction( mMoreAction );
239  }
240 
241  if ( !mToolbarActions.isEmpty() && mGUIClient->factory() ) {
242  mGUIClient->plugActionList( QLatin1String("toolbar_messagetag_actions"), mToolbarActions );
243  }
244 }
245 
246 void TagActionManager::newTagEntries (const QList<Nepomuk2::Query::Result> &results)
247 {
248  foreach (const Nepomuk2::Query::Result &result, results) {
249  Nepomuk2::Resource resource = result.resource();
250  mTags.append( MailCommon::Tag::fromNepomuk( resource ) );
251  }
252 }
253 
254 void TagActionManager::finishedTagListing()
255 {
256  mTagQueryClient->close();
257  mTagQueryClient->deleteLater();
258  mTagQueryClient = 0;
259  if ( mTags.isEmpty() )
260  return;
261  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
262  createTagActions();
263 }
264 
265 
266 void TagActionManager::updateActionStates( int numberOfSelectedMessages,
267  const Akonadi::Item &selectedItem )
268 {
269  mNewTagUri.clear();
270  QMap<QString,KToggleAction*>::const_iterator it = mTagActions.constBegin();
271  QMap<QString,KToggleAction*>::const_iterator end = mTagActions.constEnd();
272  if ( numberOfSelectedMessages == 1 )
273  {
274  Q_ASSERT( selectedItem.isValid() );
275  mAsyncNepomukRetriver->requestResource( selectedItem.url() );
276  }
277  else if ( numberOfSelectedMessages > 1 ) {
278  for ( ; it != end; ++it ) {
279  Nepomuk2::Tag tag( it.key() );
280  it.value()->setChecked( false );
281  it.value()->setEnabled( true );
282  it.value()->setText( i18n("Toggle Message Tag %1", tag.label() ) );
283  }
284  }
285  else {
286  for ( ; it != end; ++it ) {
287  it.value()->setEnabled( false );
288  }
289  }
290 }
291 
292 void TagActionManager::slotLoadedResourceForUpdateActionStates(const QUrl& uri, const Nepomuk2::Resource& res)
293 {
294  QMap<QString,KToggleAction*>::const_iterator it = mTagActions.constBegin();
295  QMap<QString,KToggleAction*>::const_iterator end = mTagActions.constEnd();
296  for ( ; it != end; ++it ) {
297  const bool hasTag = res.tags().contains( Nepomuk2::Tag( it.key() ) );
298  it.value()->setChecked( hasTag );
299  it.value()->setEnabled( true );
300  }
301 }
302 
303 
304 void TagActionManager::tagsChanged()
305 {
306  mTags.clear(); // re-read the tags
307  createActions();
308 }
309 
310 void TagActionManager::resourceCreated(const Nepomuk2::Resource& res,const QList<QUrl>&)
311 {
312  const QList<QUrl> checked = checkedTags();
313 
314  clearActions();
315  mTags.append( MailCommon::Tag::fromNepomuk( res ) );
316  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
317  createTagActions();
318 
319  checkTags( checked );
320 }
321 
322 void TagActionManager::resourceRemoved(const QUrl& url,const QList<QUrl>&)
323 {
324  foreach( const MailCommon::Tag::Ptr &tag, mTags ) {
325  if(tag->nepomukResourceUri == url) {
326  mTags.removeAll(tag);
327  break;
328  }
329  }
330 
331  const QList<QUrl> checked = checkedTags();
332 
333  clearActions();
334  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
335  createTagActions();
336 
337  checkTags( checked );
338 }
339 
340 void TagActionManager::propertyChanged(const Nepomuk2::Resource& res)
341 {
342  foreach( const MailCommon::Tag::Ptr &tag, mTags ) {
343  if(tag->nepomukResourceUri == res.uri()) {
344  mTags.removeAll(tag);
345  break;
346  }
347  }
348  mTags.append( MailCommon::Tag::fromNepomuk( res ) );
349 
350  QList<QUrl> checked = checkedTags();
351 
352  clearActions();
353  qSort( mTags.begin(), mTags.end(), MailCommon::Tag::compare );
354  createTagActions();
355 
356  checkTags( checked );
357 }
358 
359 void TagActionManager::newTagActionClicked()
360 {
361  QPointer<MailCommon::AddTagDialog> dialog = new MailCommon::AddTagDialog(QList<KActionCollection*>() << mActionCollection, 0);
362  dialog->setTags(mTags);
363  if ( dialog->exec() ) {
364  mNewTagUri = dialog->nepomukUrl();
365  // Assign tag to all selected items right away
366  emit tagActionTriggered( mNewTagUri );
367  }
368  delete dialog;
369 }
370 
371 void TagActionManager::checkTags(const QList< QUrl >& tags)
372 {
373  foreach( const QUrl &url, tags ) {
374  const QString str = url.toString();
375  if ( mTagActions.contains( str ) ) {
376  mTagActions[str]->setChecked( true );
377  }
378  }
379 }
380 
381 QList< QUrl > TagActionManager::checkedTags() const
382 {
383  QMap<QString,KToggleAction*>::const_iterator it = mTagActions.constBegin();
384  QMap<QString,KToggleAction*>::const_iterator end = mTagActions.constEnd();
385  QList<QUrl> checked;
386  for ( ; it != end; ++it ) {
387  if ( it.value()->isChecked() ) {
388  checked << it.key();
389  }
390  }
391 
392  return checked;
393 }
394 
395 #include "tagactionmanager.moc"
KXMLGUIClient
tagactionmanager.h
KMail::TagActionManager::~TagActionManager
~TagActionManager()
Definition: tagactionmanager.cpp:86
KMail::MessageActions
Manages common actions that can be performed on one or more messages.
Definition: messageactions.h:59
KMail::TagActionManager::tagMoreActionClicked
void tagMoreActionClicked()
Emitted when we want to select more action.
KMail::TagActionManager::tagActionTriggered
void tagActionTriggered(const QString &tagLabel)
Emitted when one of the tagging actions was triggered.
QObject
messageactions.h
s_numberMaxTag
static int s_numberMaxTag
Definition: tagactionmanager.cpp:50
KMail::TagActionManager::clearActions
void clearActions()
Removes all actions from the GUI again.
Definition: tagactionmanager.cpp:90
KMail::TagActionManager::updateActionStates
void updateActionStates(int numberOfSelectedMessages, const Akonadi::Item &selectedItem)
Updates the state of the toggle actions of all tags.
Definition: tagactionmanager.cpp:266
KMail::TagActionManager::createActions
void createActions()
Creates and plugs all tag actions.
Definition: tagactionmanager.cpp:160
QMap
Definition: kmmainwidget.h:58
QList
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:52
KMail::MessageActions::messageStatusMenu
KActionMenu * messageStatusMenu() const
Definition: messageactions.h:88
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:58:52 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

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