19 #include <config-messageviewer.h>
25 #include <kmessagebox.h>
26 #include <kopenwithdialog.h>
28 #include <kmimetypetrader.h>
31 #include <qsocketnotifier.h>
36 #ifdef HAVE_SYS_INOTIFY_H
39 #include <sys/inotify.h>
40 #include <sys/ioctl.h>
43 namespace MessageViewer {
48 mMimeType( mimeType ),
49 mOpenWith( openWith ),
51 mParentWidget( parentWidget ),
52 mHaveInotify( false ),
54 mEditorRunning( false ),
55 mFileModified( true ),
58 assert( mUrl.isLocalFile() );
59 mTimer.setSingleShot(
true );
60 connect( &mTimer, SIGNAL(timeout()), SLOT(checkEditDone()) );
68 KService::Ptr offer = KMimeTypeTrader::self()->preferredService( mMimeType, QLatin1String(
"Application") );
69 if ( mOpenWith || !offer ) {
72 QString(), mParentWidget ) );
73 int dlgrc = dlg->exec();
75 offer = dlg->service();
77 if ( !dlgrc || !offer )
82 #ifdef HAVE_SYS_INOTIFY_H
84 mInotifyFd = inotify_init();
85 if ( mInotifyFd > 0 ) {
86 mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().toLatin1(), IN_CLOSE | IN_OPEN | IN_MODIFY );
87 if ( mInotifyWatch >= 0 ) {
88 QSocketNotifier *sn =
new QSocketNotifier( mInotifyFd, QSocketNotifier::Read,
this );
89 connect( sn, SIGNAL(activated(
int)), SLOT(inotifyEvent()) );
91 mFileModified =
false;
94 kWarning() <<
"Failed to activate INOTIFY!";
99 const QStringList params = KRun::processDesktopExec( *offer, list,
false );
100 mEditor =
new KProcess(
this );
101 mEditor->setProgram( params );
102 connect( mEditor, SIGNAL(finished(
int,QProcess::ExitStatus)),
103 SLOT(editorExited()) );
105 if ( !mEditor->waitForStarted() )
107 mEditorRunning =
true;
113 void EditorWatcher::inotifyEvent()
115 assert( mHaveInotify );
116 #ifdef HAVE_SYS_INOTIFY_H
119 ioctl( mInotifyFd, FIONREAD, &pending );
120 while ( pending > 0 ) {
121 int size = read( mInotifyFd, buffer, qMin( pending, (
int)
sizeof(buffer) ) );
127 struct inotify_event *
event = (
struct inotify_event *) &buffer[offset];
128 size -=
sizeof(
struct inotify_event ) + event->len;
129 offset +=
sizeof(
struct inotify_event ) + event->len;
130 if ( event->mask & IN_OPEN )
132 if ( event->mask & IN_CLOSE )
134 if ( event->mask & IN_MODIFY )
135 mFileModified =
true;
143 void EditorWatcher::editorExited()
145 mEditorRunning =
false;
149 void EditorWatcher::checkEditDone()
151 if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone )
154 static QStringList readOnlyMimeTypes;
155 if ( readOnlyMimeTypes.isEmpty() ) {
156 readOnlyMimeTypes << QLatin1String(
"message/rfc822")
157 << QLatin1String(
"application/pdf");
165 const bool isReadOnlyMimeType = ( readOnlyMimeTypes.contains( mMimeType ) ||
166 mMimeType.startsWith( QLatin1String(
"image/") ) );
170 if ( mEditTime.elapsed() <= 3000 && !isReadOnlyMimeType ) {
171 KMessageBox::information( mParentWidget,
172 i18n(
"KMail is unable to detect when the chosen editor is closed. "
173 "To avoid data loss, editing the attachment will be aborted." ),
174 i18n(
"Unable to edit attachment" ),
175 QLatin1String(
"UnableToEditAttachment") );
182 #include "editorwatcher.moc"
void editDone(MessageViewer::EditorWatcher *watcher)
A QPointer which when destructed, deletes the object it points to.
EditorWatcher(const KUrl &url, const QString &mimeType, bool openWith, QObject *parent, QWidget *parentWidget)
Constructs an EditorWatcher.