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

messageviewer

  • sources
  • kde-4.14
  • kdepim
  • messageviewer
  • viewer
editorwatcher.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 
19 #include <config-messageviewer.h>
20 #include "editorwatcher.h"
21 #include "utils/autoqpointer.h"
22 
23 #include <kdebug.h>
24 #include <klocale.h>
25 #include <kmessagebox.h>
26 #include <kopenwithdialog.h>
27 #include <kprocess.h>
28 #include <kmimetypetrader.h>
29 #include <krun.h>
30 
31 #include <qsocketnotifier.h>
32 
33 #include <cassert>
34 
35 // inotify stuff taken from kdelibs/kio/kio/kdirwatch.cpp
36 #ifdef HAVE_SYS_INOTIFY_H
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <sys/inotify.h>
40 #include <sys/ioctl.h>
41 #endif
42 
43 namespace MessageViewer {
44 EditorWatcher::EditorWatcher( const KUrl & url, const QString &mimeType, OpenWithOption option,
45  QObject * parent, QWidget *parentWidget ) :
46  QObject( parent ),
47  mUrl( url ),
48  mMimeType( mimeType ),
49  mEditor( 0 ),
50  mParentWidget( parentWidget ),
51  mInotifyFd(-1),
52  mInotifyWatch(-1),
53  mOpenWithOption( option ),
54  mHaveInotify( false ),
55  mFileOpen( false ),
56  mEditorRunning( false ),
57  mFileModified( true ), // assume the worst unless we know better
58  mDone( false )
59 {
60  assert( mUrl.isLocalFile() );
61  mTimer.setSingleShot( true );
62  connect( &mTimer, SIGNAL(timeout()), SLOT(checkEditDone()) );
63 }
64 
65 EditorWatcher::~EditorWatcher()
66 {
67 #ifdef HAVE_SYS_INOTIFY_H
68  ::close( mInotifyFd );
69 #endif
70 }
71 
72 EditorWatcher::ErrorEditorWatcher EditorWatcher::start()
73 {
74  // find an editor
75  KUrl::List list;
76  list.append( mUrl );
77  KService::Ptr offer = KMimeTypeTrader::self()->preferredService( mMimeType, QLatin1String("Application") );
78  if ( (mOpenWithOption == OpenWithDialog) || !offer ) {
79  AutoQPointer<KOpenWithDialog> dlg( new KOpenWithDialog( list, i18n("Edit with:"),
80  QString(), mParentWidget ) );
81  const int dlgrc = dlg->exec();
82  if ( dlgrc && dlg ) {
83  offer = dlg->service();
84  }
85  if ( !dlgrc )
86  return Canceled;
87  if ( !offer )
88  return NoServiceFound;
89  }
90 
91 #ifdef HAVE_SYS_INOTIFY_H
92  // monitor file
93  mInotifyFd = inotify_init();
94  if ( mInotifyFd > 0 ) {
95  (void)fcntl(mInotifyFd, F_SETFD, FD_CLOEXEC);
96  mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().toLatin1(), IN_CLOSE | IN_OPEN | IN_MODIFY | IN_ATTRIB );
97  if ( mInotifyWatch >= 0 ) {
98  QSocketNotifier *sn = new QSocketNotifier( mInotifyFd, QSocketNotifier::Read, this );
99  connect( sn, SIGNAL(activated(int)), SLOT(inotifyEvent()) );
100  mHaveInotify = true;
101  mFileModified = false;
102  }
103  } else {
104  kWarning() << "Failed to activate INOTIFY!";
105  }
106 #endif
107 
108  // start the editor
109  const QStringList params = KRun::processDesktopExec( *offer, list, false );
110  mEditor = new KProcess( this );
111  mEditor->setProgram( params );
112  connect( mEditor, SIGNAL(finished(int,QProcess::ExitStatus)),
113  SLOT(editorExited()) );
114  mEditor->start();
115  if ( !mEditor->waitForStarted() )
116  return CannotStart;
117  mEditorRunning = true;
118 
119  mEditTime.start();
120  return NoError;
121 }
122 
123 bool EditorWatcher::fileChanged() const
124 {
125  return mFileModified;
126 }
127 
128 KUrl EditorWatcher::url() const
129 {
130  return mUrl;
131 }
132 
133 void EditorWatcher::inotifyEvent()
134 {
135  assert( mHaveInotify );
136 
137 #ifdef HAVE_SYS_INOTIFY_H
138  int pending = -1;
139  int offsetStartRead = 0; // where we read into buffer
140  char buf[8192];
141  assert( mInotifyFd > -1 );
142  ioctl( mInotifyFd, FIONREAD, &pending );
143 
144  while ( pending > 0 ) {
145 
146  const int bytesToRead = qMin( pending, (int)sizeof( buf ) - offsetStartRead );
147 
148  int bytesAvailable = read( mInotifyFd, &buf[offsetStartRead], bytesToRead );
149  pending -= bytesAvailable;
150  bytesAvailable += offsetStartRead;
151  offsetStartRead = 0;
152 
153  int offsetCurrent = 0;
154  while ( bytesAvailable >= (int)sizeof( struct inotify_event ) ) {
155  const struct inotify_event * const event = (struct inotify_event *) &buf[offsetCurrent];
156  const int eventSize = sizeof( struct inotify_event ) + event->len;
157  if ( bytesAvailable < eventSize ) {
158  break;
159  }
160 
161  bytesAvailable -= eventSize;
162  offsetCurrent += eventSize;
163  if ( event->mask & IN_OPEN ) {
164  mFileOpen = true;
165  }
166  if ( event->mask & IN_CLOSE ) {
167  mFileOpen = false;
168  }
169  if ( event->mask & (IN_MODIFY|IN_ATTRIB) ) {
170  mFileModified = true;
171  }
172 
173  }
174  if (bytesAvailable > 0) {
175  // copy partial event to beginning of buffer
176  memmove(buf, &buf[offsetCurrent], bytesAvailable);
177  offsetStartRead = bytesAvailable;
178  }
179  }
180 #endif
181 
182  mTimer.start( 500 );
183 
184 }
185 
186 void EditorWatcher::editorExited()
187 {
188  mEditorRunning = false;
189  mTimer.start( 500 );
190 }
191 
192 void EditorWatcher::checkEditDone()
193 {
194  if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone )
195  return;
196 
197  static QStringList readOnlyMimeTypes;
198  if ( readOnlyMimeTypes.isEmpty() ) {
199  readOnlyMimeTypes << QLatin1String("message/rfc822")
200  << QLatin1String("application/pdf");
201  }
202 
203  // protect us against double-deletion by calling this method again while
204  // the subeventloop of the message box is running
205  mDone = true;
206 
207  // check if it's a mime type that's mostly handled read-only
208  const bool isReadOnlyMimeType = ( readOnlyMimeTypes.contains( mMimeType ) ||
209  mMimeType.startsWith( QLatin1String("image/") ) );
210 
211  // nobody can edit that fast, we seem to be unable to detect
212  // when the editor will be closed
213  if ( mEditTime.elapsed() <= 3000 && !isReadOnlyMimeType ) {
214  KMessageBox::information( mParentWidget,
215  i18n( "KMail is unable to detect when the chosen editor is closed. "
216  "To avoid data loss, editing the attachment will be aborted." ),
217  i18n( "Unable to edit attachment" ),
218  QLatin1String("UnableToEditAttachment") );
219  }
220 
221  emit editDone( this );
222  deleteLater();
223 }
224 }
editorwatcher.h
QWidget
MessageViewer::EditorWatcher::EditorWatcher
EditorWatcher(const KUrl &url, const QString &mimeType, OpenWithOption option, QObject *parent, QWidget *parentWidget)
Constructs an EditorWatcher.
Definition: editorwatcher.cpp:44
QSocketNotifier
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
MessageViewer::EditorWatcher::editDone
void editDone(MessageViewer::EditorWatcher *watcher)
QObject::event
virtual bool event(QEvent *e)
MessageViewer::EditorWatcher::start
ErrorEditorWatcher start()
Definition: editorwatcher.cpp:72
QTime::elapsed
int elapsed() const
MessageViewer::EditorWatcher::NoServiceFound
Definition: editorwatcher.h:50
MessageViewer::AutoQPointer
A QPointer which when destructed, deletes the object it points to.
Definition: autoqpointer.h:38
autoqpointer.h
MessageViewer::EditorWatcher::OpenWithDialog
Definition: editorwatcher.h:44
QObject
QList::isEmpty
bool isEmpty() const
MessageViewer::EditorWatcher::OpenWithOption
OpenWithOption
Definition: editorwatcher.h:43
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
MessageViewer::EditorWatcher::NoError
Definition: editorwatcher.h:52
QObject::deleteLater
void deleteLater()
QString
QStringList
MessageViewer::EditorWatcher::fileChanged
bool fileChanged() const
Definition: editorwatcher.cpp:123
MessageViewer::EditorWatcher::Canceled
Definition: editorwatcher.h:49
QLatin1String
MessageViewer::EditorWatcher::ErrorEditorWatcher
ErrorEditorWatcher
Definition: editorwatcher.h:47
MessageViewer::EditorWatcher::url
KUrl url() const
Definition: editorwatcher.cpp:128
QTimer::start
void start(int msec)
QTime::start
void start()
MessageViewer::EditorWatcher::~EditorWatcher
~EditorWatcher()
Definition: editorwatcher.cpp:65
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
MessageViewer::EditorWatcher::CannotStart
Definition: editorwatcher.h:51
QTimer::setSingleShot
void setSingleShot(bool singleShot)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:32:45 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

messageviewer

Skip menu "messageviewer"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

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