2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
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.
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.
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.
19 #include <config-messageviewer.h>
20 #include "editorwatcher.h"
21 #include "autoqpointer.h"
25 #include <kmessagebox.h>
26 #include <kopenwithdialog.h>
28 #include <kmimetypetrader.h>
31 #include <qsocketnotifier.h>
35 // inotify stuff taken from kdelibs/kio/kio/kdirwatch.cpp
36 #ifdef HAVE_SYS_INOTIFY_H
39 #include <sys/inotify.h>
40 #include <sys/ioctl.h>
43 namespace MessageViewer
{
44 EditorWatcher::EditorWatcher( const KUrl
& url
, const QString
&mimeType
, bool openWith
,
45 QObject
* parent
, QWidget
*parentWidget
) :
48 mMimeType( mimeType
),
49 mOpenWith( openWith
),
51 mParentWidget( parentWidget
),
52 mHaveInotify( false ),
54 mEditorRunning( false ),
55 mFileModified( true ), // assume the worst unless we know better
58 assert( mUrl
.isLocalFile() );
59 mTimer
.setSingleShot( true );
60 connect( &mTimer
, SIGNAL(timeout()), SLOT(checkEditDone()) );
63 bool EditorWatcher::start()
68 KService::Ptr offer
= KMimeTypeTrader::self()->preferredService( mMimeType
, "Application" );
69 if ( mOpenWith
|| !offer
) {
71 AutoQPointer
<KOpenWithDialog
> dlg( new KOpenWithDialog( list
, i18n("Edit with:"),
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 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
<< "message/rfc822"
157 << "application/pdf";
160 // protect us against double-deletion by calling this method again while
161 // the subeventloop of the message box is running
164 // check if it's a mime type that's mostly handled read-only
165 const bool isReadOnlyMimeType
= ( readOnlyMimeTypes
.contains( mMimeType
) ||
166 mMimeType
.startsWith( "image/" ) );
168 // nobody can edit that fast, we seem to be unable to detect
169 // when the editor will be closed
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 "UnableToEditAttachment" );
178 emit
editDone( this );
182 #include "editorwatcher.moc"