singlefileresource.h 6.89 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
    Copyright (c) 2008 Bertjan Broeksema <b.broeksema@kdemail.net>
    Copyright (c) 2008 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#ifndef AKONADI_SINGLEFILERESOURCE_H
#define AKONADI_SINGLEFILERESOURCE_H

#include "singlefileresourcebase.h"

Volker Krause's avatar
Volker Krause committed
26
#include <akonadi/entitydisplayattribute.h>
27

28
#include <kio/job.h>
29
#include <KDirWatch>
30
#include <KLocale>
31
#include <KStandardDirs>
32

33
34
#include <QFile>

35
36
37
38
39
40
41
42
43
44
45
46
namespace Akonadi
{

/**
 * Base class for single file based resources.
 */
template <typename Settings>
class SingleFileResource : public SingleFileResourceBase
{
  public:
    SingleFileResource( const QString &id ) : SingleFileResourceBase( id )
    {
47
48
      // The resource needs network when the path refers to a non local file.
      setNeedsNetwork( !KUrl( Settings::self()->path() ).isLocalFile() );
49
50
51
52
53
54
55
    }

    /**
     * Indicate that there are pending changes.
     */
    void fileDirty()
    {
Volker Krause's avatar
Volker Krause committed
56
      if( !mDirtyTimer.isActive() ) {
57
58
59
60
61
62
63
64
65
66
        mDirtyTimer.setInterval( Settings::self()->autosaveInterval() * 60 * 1000 );
        mDirtyTimer.start();
      }
    }

    /**
     * Read changes from the backend file.
     */
    void readFile()
    {
67
68
      if ( KDirWatch::self()->contains( mCurrentUrl.path() ) )
        KDirWatch::self()->removeFile( mCurrentUrl.path() );
69

70
71
      const bool nameWasChanged = mCurrentUrl.fileName() != name() && !mCurrentUrl.isEmpty();

72
73
74
75
76
77
      if ( Settings::self()->path().isEmpty() ) {
        emit status( Broken, i18n( "No file selected." ) );
        return;
      }

      mCurrentUrl = KUrl( Settings::self()->path() );
78
79
80
81
82

      if ( mCurrentUrl.isLocalFile() )
      {
        if ( !nameWasChanged )
          setName( mCurrentUrl.fileName() );
Volker Krause's avatar
Volker Krause committed
83

84
85
86
87
        // check if the file does not exist yet, if so, create it
        if ( !QFile::exists( mCurrentUrl.path() ) ) {
          QFile f( mCurrentUrl.path() );
          if ( f.open( QIODevice::WriteOnly ) && f.resize( 0 ) ) {
Bertjan Broeksema's avatar
Bertjan Broeksema committed
88
            emit status( Idle, i18nc( "@info:status", "Ready" ) );
89
90
91
92
93
94
95
96
97
          } else {
            emit status( Broken, i18n( "Could not create file '%1'.", mCurrentUrl.prettyUrl() ) );
            mCurrentUrl.clear();
            return;
          }
        }

        if ( !readFromFile( mCurrentUrl.path() ) ) {
          mCurrentUrl = KUrl(); // reset so we don't accidentally overwrite the file
98
99
100
          return;
        }

101
102
        if ( Settings::self()->monitorFile() )
          KDirWatch::self()->addFile( mCurrentUrl.path() );
Volker Krause's avatar
Volker Krause committed
103

Bertjan Broeksema's avatar
Bertjan Broeksema committed
104
        emit status( Idle, i18nc( "@info:status", "Ready" ) );
105
        synchronize();
106
      }
107
108
109
110
111
112
113
114
115
116
      else
      {
        if ( mDownloadJob )
        {
          emit error( i18n( "Another download is still in progress." ) );
          return;
        }

        if ( mUploadJob )
        {
117
          emit error( i18n( "Another file upload is still in progress." ) );
118
119
          return;
        }
120

121
        KGlobal::ref();
Volker Krause's avatar
Volker Krause committed
122

123
        // NOTE: Test what happens with remotefile -> save, close before save is finished.
Bertjan Broeksema's avatar
Bertjan Broeksema committed
124
        mDownloadJob = KIO::file_copy( mCurrentUrl, KUrl( cacheFile() ), -1, KIO::Overwrite | KIO::DefaultFlags | KIO::HideProgressInfo );
125
126
        connect( mDownloadJob, SIGNAL( result( KJob * ) ),
                SLOT( slotDownloadJobResult( KJob * ) ) );
Bertjan Broeksema's avatar
Bertjan Broeksema committed
127
128
        connect( mDownloadJob, SIGNAL( percent( KJob *, unsigned long ) ),
                 SLOT( handleProgress( KJob *, unsigned long ) ) );
129
130
131

        emit status( Running, i18n( "Downloading remote file." ) );
      }
132
133
134
135
136
137
138
139
    }

    /**
     * Write changes to the backend file.
     */
    void writeFile()
    {
      if ( Settings::self()->readOnly() ) {
140
        emit error( i18n( "Trying to write to a read-only file: '%1'.", Settings::self()->path() ) );
141
142
143
144
145
146
147
148
149
150
151
152
        return;
      }

      mDirtyTimer.stop();

      // We don't use the Settings::self()->path() here as that might have changed
      // and in that case it would probably cause data lose.
      if ( mCurrentUrl.isEmpty() ) {
        emit status( Broken, i18n( "No file specified." ) );
        return;
      }

153
154
155
156
157
158
      if ( mCurrentUrl.isLocalFile() ) {
        KDirWatch::self()->stopScan();
        const bool writeResult = writeToFile( mCurrentUrl.path() );
        KDirWatch::self()->startScan();
        if ( !writeResult )
          return;
159

Bertjan Broeksema's avatar
Bertjan Broeksema committed
160
        emit status( Idle, i18nc( "@info:status", "Ready" ) );
161
162
163
164
165
166
167
168
      } else {
        // Check if there is a download or an upload in progress.
        if ( mDownloadJob ) {
          emit error( i18n( "A download is still in progress." ) );
          return;
        }

        if ( mUploadJob ) {
169
          emit error( i18n( "Another file upload is still in progress." ) );
170
171
172
173
174
175
176
177
178
          return;
        }

        // Write te items to the localy cached file.
        if ( !writeToFile( cacheFile() ) )
          return;

        KGlobal::ref();
        // Start a job to upload the localy cached file to the remote location.
Bertjan Broeksema's avatar
Bertjan Broeksema committed
179
        mUploadJob = KIO::file_copy( KUrl( cacheFile() ), mCurrentUrl, -1, KIO::Overwrite | KIO::DefaultFlags | KIO::HideProgressInfo );
180
181
        connect( mUploadJob, SIGNAL( result( KJob * ) ),
                SLOT( slotUploadJobResult( KJob * ) ) );
Bertjan Broeksema's avatar
Bertjan Broeksema committed
182
183
        connect( mUploadJob, SIGNAL( percent( KJob *, unsigned long ) ),
                 SLOT( handleProgress( KJob *, unsigned long ) ) );
184
185
186

        emit status( Running, i18n( "Uploading cached file to remote location." ) );
      }
187
    }
Volker Krause's avatar
Volker Krause committed
188
189
190
191
192
193
194

  protected:
    void retrieveCollections()
    {
      Collection c;
      c.setParent( Collection::root() );
      c.setRemoteId( Settings::self()->path() );
195
      c.setName( identifier() );
Volker Krause's avatar
Volker Krause committed
196
197
198
      QStringList mimeTypes;
      c.setContentMimeTypes( mSupportedMimetypes );
      if ( Settings::self()->readOnly() ) {
199
        c.setRights( Collection::CanChangeCollection );
Volker Krause's avatar
Volker Krause committed
200
201
202
203
204
      } else {
        Collection::Rights rights;
        rights |= Collection::CanChangeItem;
        rights |= Collection::CanCreateItem;
        rights |= Collection::CanDeleteItem;
205
        rights |= Collection::CanChangeCollection;
Volker Krause's avatar
Volker Krause committed
206
207
        c.setRights( rights );
      }
Volker Krause's avatar
Volker Krause committed
208
      EntityDisplayAttribute* attr = c.attribute<EntityDisplayAttribute>( Collection::AddIfMissing );
209
210
      attr->setDisplayName( name() );
      attr->setIconName( mCollectionIcon );
Volker Krause's avatar
Volker Krause committed
211
212
213
214
      Collection::List list;
      list << c;
      collectionsRetrieved( list );
    }
215
216
217
218
219
};

}

#endif