~ubuntu-branches/ubuntu/intrepid/digikam/intrepid

« back to all changes in this revision

Viewing changes to digikam/utilities/cameragui/umscamera.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-07-17 20:25:39 UTC
  • mfrom: (1.3.2 upstream) (37 hardy)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20080717202539-1bw3w3nrsso7yj4z
* New upstream release
  - digiKam 0.9.4 Release Plan (KDE3) ~ 13 July 08 (Closes: #490144)
* DEB_CONFIGURE_EXTRA_FLAGS := --without-included-sqlite3
* Debhelper compatibility level V7
* Install pixmaps in debian/*.install
* Add debian/digikam.lintian-overrides

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* ============================================================
2
 
 * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
3
 
 *         Gilles Caulier <caulier dot gilles at free.fr> 
4
 
 * Date  : 2004-12-21
5
 
 * Description : 
6
 
 * 
7
 
 * Copyright 2004-2005 by Renchi Raju
8
 
 * Copyright 2005-2006 by Gilles Caulier
 
2
 *
 
3
 * This file is a part of digiKam project
 
4
 * http://www.digikam.org
 
5
 *
 
6
 * Date        : 2004-12-21
 
7
 * Description : USB Mass Storage camera interface
 
8
 *
 
9
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 
10
 * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> 
9
11
 *
10
12
 * This program is free software; you can redistribute it
11
13
 * and/or modify it under the terms of the GNU General
12
14
 * Public License as published by the Free Software Foundation;
13
15
 * either version 2, or (at your option)
14
16
 * any later version.
15
 
 * 
 
17
 *
16
18
 * This program is distributed in the hope that it will be useful,
17
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
21
 * GNU General Public License for more details.
20
 
 * 
 
22
 *
21
23
 * ============================================================ */
22
24
 
23
25
// C Ansi includes.
37
39
#include <qfile.h>
38
40
#include <qstringlist.h>
39
41
#include <qdeepcopy.h>
 
42
#include <qwmatrix.h>
40
43
 
41
44
// KDE includes.
42
45
 
43
 
#include <ktempfile.h>
44
 
#include <kdebug.h>
45
 
 
46
 
// LibKExif includes.
47
 
 
48
 
#include <libkexif/kexifdata.h>
 
46
#include <klocale.h>
 
47
#include <kfilemetainfo.h>
 
48
 
 
49
// LibKDcraw includes.
 
50
 
 
51
#include <libkdcraw/kdcraw.h>
49
52
 
50
53
// Local includes.
51
54
 
52
 
#include "dcraw_parse.h"
53
 
#include "albumsettings.h"
 
55
#include "ddebug.h"
 
56
#include "dimg.h"
 
57
#include "dmetadata.h"
54
58
#include "umscamera.h"
55
59
 
56
 
UMSCamera::UMSCamera(const QString& model,
57
 
                     const QString& port,
58
 
                     const QString& path)
59
 
    : DKCamera(model, port, path)
60
 
{
61
 
    m_cancel = false;    
62
 
 
63
 
    AlbumSettings* settings = AlbumSettings::instance();
64
 
    m_imageFilter = QDeepCopy<QString>(settings->getImageFileFilter());
65
 
    m_movieFilter = QDeepCopy<QString>(settings->getMovieFileFilter());
66
 
    m_audioFilter = QDeepCopy<QString>(settings->getAudioFileFilter());
67
 
    m_rawFilter   = QDeepCopy<QString>(settings->getRawFileFilter());
68
 
 
69
 
    m_imageFilter = m_imageFilter.lower(); 
70
 
    m_movieFilter = m_movieFilter.lower();     
71
 
    m_audioFilter = m_audioFilter.lower();     
72
 
    m_rawFilter   = m_rawFilter.lower();     
 
60
namespace Digikam
 
61
{
 
62
 
 
63
UMSCamera::UMSCamera(const QString& title, const QString& model, const QString& port, const QString& path)
 
64
         : DKCamera(title, model, port, path)
 
65
{
 
66
    m_cancel = false;
73
67
}
74
68
 
75
69
UMSCamera::~UMSCamera()
76
70
{
77
71
}
78
72
 
79
 
bool UMSCamera::connect()
 
73
bool UMSCamera::doConnect()
80
74
{
81
 
    return true;    
 
75
    return true;
82
76
}
83
77
 
84
78
void UMSCamera::cancel()
87
81
    m_cancel = true;
88
82
}
89
83
 
90
 
void UMSCamera::getAllFolders(const QString& folder,
91
 
                              QStringList& subFolderList)
 
84
void UMSCamera::getAllFolders(const QString& folder, QStringList& subFolderList)
92
85
{
93
86
    m_cancel = false;
94
87
    subFolderList.clear();
96
89
    listFolders(folder, subFolderList);
97
90
}
98
91
 
99
 
bool UMSCamera::getItemsInfoList(const QString& folder,
100
 
                                 GPItemInfoList& infoList)
 
92
bool UMSCamera::getItemsInfoList(const QString& folder, GPItemInfoList& infoList, bool getImageDimensions)
101
93
{
102
94
    m_cancel = false;
103
95
    infoList.clear();
117
109
        ++it;
118
110
 
119
111
        QString mime = mimeType(fi->extension(false).lower());
 
112
 
120
113
        if (!mime.isEmpty())
121
114
        {
122
115
            GPItemInfo info;
 
116
            QSize dims(-1, -1);
 
117
 
 
118
            if (getImageDimensions)
 
119
            {
 
120
                if (mime == QString("image/x-raw"))
 
121
                {
 
122
                    DMetadata metaData(fi->filePath());
 
123
                    dims = metaData.getImageDimensions();
 
124
                }
 
125
                else
 
126
                {
 
127
                    KFileMetaInfo meta(fi->filePath());
 
128
                    if (meta.isValid())
 
129
                    {
 
130
                        if (meta.containsGroup("Jpeg EXIF Data"))
 
131
                            dims = meta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
 
132
                        else if (meta.containsGroup("General"))
 
133
                            dims = meta.group("General").item("Dimensions").value().toSize();
 
134
                        else if (meta.containsGroup("Technical"))
 
135
                            dims = meta.group("Technical").item("Dimensions").value().toSize();
 
136
                    }
 
137
                }
 
138
            }
 
139
 
123
140
            info.name             = fi->fileName();
124
 
            info.folder           = folder;
 
141
            info.folder           = !folder.endsWith("/") ? folder + QString("/") : folder;
125
142
            info.mime             = mime;
126
143
            info.mtime            = fi->lastModified().toTime_t();
127
144
            info.size             = fi->size();
128
 
            info.width            = -1; // todo
129
 
            info.height           = -1; // todo
130
 
            info.downloaded       = -1; 
 
145
            info.width            = dims.width();
 
146
            info.height           = dims.height();
 
147
            info.downloaded       = GPItemInfo::DownloadUnknow;
131
148
            info.readPermissions  = fi->isReadable();
132
149
            info.writePermissions = fi->isWritable();
133
 
        
 
150
 
134
151
            infoList.append(info);
135
152
        }
136
153
    }
137
 
    
 
154
 
138
155
    return true;
139
156
}
140
157
 
142
159
{
143
160
    m_cancel = false;
144
161
 
145
 
    // In 1st, we trying to get thumbnail from Exif data if we are JPEG file.
146
 
 
147
 
    KExifData exifData;
148
 
    
149
 
    if (exifData.readFromFile(folder + "/" + itemName))
150
 
    {
151
 
        thumbnail = exifData.getThumbnail();
152
 
        if (!thumbnail.isNull())
153
 
           return true;
154
 
    }
155
 
 
156
 
    // In 2th, we trying to get thumbnail from '.thm' files if we didn't manage to get
 
162
    // JPEG files: try to get thumbnail from Exif data.
 
163
 
 
164
    DMetadata metadata(QFile::encodeName(folder + QString("/") + itemName));
 
165
    thumbnail = metadata.getExifThumbnail(true);
 
166
    if (!thumbnail.isNull())
 
167
        return true;
 
168
 
 
169
    // RAW files : try to extract embedded thumbnail using dcraw
 
170
 
 
171
    KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, QString(folder + QString("/") + itemName));
 
172
    if (!thumbnail.isNull())
 
173
        return true;
 
174
 
 
175
    // THM files: try to get thumbnail from '.thm' files if we didn't manage to get 
157
176
    // thumbnail from Exif. Any cameras provides *.thm files like JPEG files with RAW files. 
158
 
    // Using this way is always more speed than using dcraw parse utility.
 
177
    // Using this way is always speed up than ultimate loading using DImg.
 
178
    // Nota: the thumbnail extracted with this method can be in poor quality.
159
179
    // 2006/27/01 - Gilles - Tested with my Minolta Dynax 5D USM camera.
160
180
 
161
 
    QFileInfo fi(folder + "/" + itemName);
162
 
 
163
 
    if (thumbnail.load(folder + "/" + fi.baseName() + ".thm"))        // Lowercase
164
 
    {
165
 
        if (!thumbnail.isNull())
166
 
           return true;
167
 
    }
168
 
    else if (thumbnail.load(folder + "/" + fi.baseName() + ".THM"))   // Uppercase
169
 
    {
170
 
        if (!thumbnail.isNull())
171
 
           return true;
172
 
    }   
173
 
 
174
 
    // In 3rd, if file image type is TIFF, load thumb using KDELib API before to use dcraw::parse method 
175
 
    // to prevent broken 16 bits TIFF thumb.
176
 
 
177
 
    if (fi.extension().upper() == QString("TIFF") ||
178
 
        fi.extension().upper() == QString("TIF"))
179
 
    {
180
 
        thumbnail.load(folder + "/" + itemName);
181
 
    
182
 
        if (!thumbnail.isNull())
183
 
            return true;
184
 
    }
185
 
 
186
 
    // In 4th we trying to get thumbnail from RAW files using dcraw parse utility.
187
 
 
188
 
    KTempFile thumbFile(QString::null, "camerarawthumb");
189
 
    thumbFile.setAutoDelete(true);
190
 
    Digikam::DcrawParse rawFileParser;
191
 
    
192
 
    if (thumbFile.status() == 0)
193
 
    {
194
 
        if (rawFileParser.getThumbnail(QFile::encodeName(folder + "/" + itemName),
195
 
                                       QFile::encodeName(thumbFile.name())) == 0)
196
 
        {
197
 
            thumbnail.load(thumbFile.name());
198
 
            if (!thumbnail.isNull())
199
 
                return true;
200
 
        }
201
 
    }
202
 
    
203
 
    // Finaly, we trying to get thumbnail using KDELib API. This way can take a while.
204
 
    
205
 
    thumbnail.load(folder + "/" + itemName);
206
 
 
207
 
    if (!thumbnail.isNull())
 
181
    QFileInfo fi(folder + QString("/") + itemName);
 
182
 
 
183
    if (thumbnail.load(folder + QString("/") + fi.baseName() + ".thm"))        // Lowercase
 
184
    {
 
185
        if (!thumbnail.isNull())
 
186
           return true;
 
187
    }
 
188
    else if (thumbnail.load(folder + QString("/") + fi.baseName() + ".THM"))   // Uppercase
 
189
    {
 
190
        if (!thumbnail.isNull())
 
191
           return true;
 
192
    }
 
193
 
 
194
 
 
195
    // Finaly, we trying to get thumbnail using DImg API (slow).
 
196
 
 
197
    DImg dimgThumb(QFile::encodeName(folder + QString("/") + itemName));
 
198
 
 
199
    if (!dimgThumb.isNull())
 
200
    {
 
201
        thumbnail = dimgThumb.copyQImage();
208
202
        return true;
 
203
    }
209
204
 
210
205
    return false;
211
206
}
212
207
 
213
 
bool UMSCamera::getExif(const QString& ,
214
 
                        const QString& ,
215
 
                        char **, int& )
 
208
bool UMSCamera::getExif(const QString&, const QString&, char **, int&)
216
209
{
217
210
    // not necessary to implement this. read it directly from the file
218
211
    // (done in camera controller)
219
 
    kdWarning() << "exif implemented yet" << endl;
 
212
    DWarning() << "exif implemented yet in camera controller" << endl;
220
213
    return false;
221
214
}
222
215
 
223
 
bool UMSCamera::downloadItem(const QString& folder,
224
 
                             const QString& itemName,
225
 
                             const QString& saveFile)
 
216
bool UMSCamera::downloadItem(const QString& folder, const QString& itemName, const QString& saveFile)
226
217
{
227
218
    m_cancel = false;
228
219
 
229
 
    QString src  = folder + "/" + itemName;
 
220
    QString src  = folder + QString("/") + itemName;
230
221
    QString dest = saveFile;
231
 
    
 
222
 
232
223
    QFile sFile(src);
233
224
    QFile dFile(dest);
234
225
 
235
226
    if ( !sFile.open(IO_ReadOnly) )
236
227
    {
237
 
        kdWarning() << "Failed to open source file for reading: "
 
228
        DWarning() << "Failed to open source file for reading: "
238
229
                    << src << endl;
239
230
        return false;
240
231
    }
241
 
    
 
232
 
242
233
    if ( !dFile.open(IO_WriteOnly) )
243
234
    {
244
235
        sFile.close();
245
 
        kdWarning() << "Failed to open dest file for writing: "
 
236
        DWarning() << "Failed to open dest file for writing: "
246
237
                    << dest << endl;
247
238
        return false;
248
239
    }
253
244
    Q_LONG len;
254
245
    while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
255
246
    {
256
 
        if (len == -1 || dFile.writeBlock(buffer, (Q_ULONG)len) == -1)
 
247
        if (len == -1 || dFile.writeBlock(buffer, (Q_ULONG)len) != len)
257
248
        {
258
249
            sFile.close();
259
250
            dFile.close();
278
269
    return true;
279
270
}
280
271
 
281
 
bool UMSCamera::deleteItem(const QString& folder,
282
 
                           const QString& itemName)
 
272
bool UMSCamera::setLockItem(const QString& folder, const QString& itemName, bool lock)
 
273
{
 
274
    QString src  = folder + QString("/") + itemName;   
 
275
 
 
276
    if (lock)
 
277
    {
 
278
        // Lock the file to set read only flag
 
279
        if (::chmod(QFile::encodeName(src), S_IREAD) == -1)
 
280
            return false; 
 
281
    }
 
282
    else
 
283
    {
 
284
        // Unlock the file to set read/write flag
 
285
        if (::chmod(QFile::encodeName(src), S_IREAD | S_IWRITE) == -1)
 
286
            return false; 
 
287
    }
 
288
 
 
289
    return true;
 
290
}
 
291
 
 
292
bool UMSCamera::deleteItem(const QString& folder, const QString& itemName)
283
293
{
284
294
    m_cancel = false;
285
295
 
286
296
    // Any camera provide THM (thumbnail) file with real image. We need to remove it also.
287
297
 
288
 
    QFileInfo fi(folder + "/" + itemName);
289
 
 
290
 
    QFileInfo thmLo(folder + "/" + fi.baseName() + ".thm");          // Lowercase
291
 
 
292
 
    if (thmLo.exists())           
 
298
    QFileInfo fi(folder + QString("/") + itemName);
 
299
 
 
300
    QFileInfo thmLo(folder + QString("/") + fi.baseName() + ".thm");          // Lowercase
 
301
 
 
302
    if (thmLo.exists())
293
303
        ::unlink(QFile::encodeName(thmLo.filePath()));
294
304
 
295
 
    QFileInfo thmUp(folder + "/" + fi.baseName() + ".THM");          // Uppercase
 
305
    QFileInfo thmUp(folder + QString("/") + fi.baseName() + ".THM");          // Uppercase
296
306
 
297
 
    if (thmUp.exists())           
 
307
    if (thmUp.exists())
298
308
        ::unlink(QFile::encodeName(thmUp.filePath()));
299
309
 
300
310
    // Remove the real image.
301
 
    return (::unlink(QFile::encodeName(folder + "/" + itemName)) == 0);
 
311
    return (::unlink(QFile::encodeName(folder + QString("/") + itemName)) == 0);
302
312
}
303
313
 
304
 
bool UMSCamera::uploadItem(const QString& ,
305
 
                           const QString& ,
306
 
                           const QString& )
 
314
bool UMSCamera::uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
 
315
                           GPItemInfo& itemInfo, bool getImageDimensions)
307
316
{
308
 
    kdWarning() << "Upload not implemented yet" << endl;
309
 
    return false;
 
317
    m_cancel = false;
 
318
 
 
319
    QString dest = folder + QString("/") + itemName;
 
320
    QString src  = localFile;
 
321
 
 
322
    QFile sFile(src);
 
323
    QFile dFile(dest);
 
324
 
 
325
    if ( !sFile.open(IO_ReadOnly) )
 
326
    {
 
327
        DWarning() << "Failed to open source file for reading: "
 
328
                    << src << endl;
 
329
        return false;
 
330
    }
 
331
 
 
332
    if ( !dFile.open(IO_WriteOnly) )
 
333
    {
 
334
        sFile.close();
 
335
        DWarning() << "Failed to open dest file for writing: "
 
336
                    << dest << endl;
 
337
        return false;
 
338
    }
 
339
 
 
340
    const int MAX_IPC_SIZE = (1024*32);
 
341
    char buffer[MAX_IPC_SIZE];
 
342
 
 
343
    Q_LONG len;
 
344
    while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
 
345
    {
 
346
        if (len == -1 || dFile.writeBlock(buffer, (Q_ULONG)len) == -1)
 
347
        {
 
348
            sFile.close();
 
349
            dFile.close();
 
350
            return false;
 
351
        }
 
352
    }
 
353
 
 
354
    sFile.close();
 
355
    dFile.close();
 
356
 
 
357
    // set the file modification time of the uploaded file to that
 
358
    // of the original file
 
359
    struct stat st;
 
360
    ::stat(QFile::encodeName(src), &st);
 
361
 
 
362
    struct utimbuf ut;
 
363
    ut.modtime = st.st_mtime;
 
364
    ut.actime  = st.st_atime;
 
365
 
 
366
    ::utime(QFile::encodeName(dest), &ut);
 
367
 
 
368
    // Get new camera item information.
 
369
 
 
370
    QFileInfo fi(dest);
 
371
    QString mime = mimeType(fi.extension(false).lower());
 
372
 
 
373
    if (!mime.isEmpty())
 
374
    {
 
375
        QSize dims(-1, -1);
 
376
 
 
377
        if (getImageDimensions)
 
378
        {
 
379
            if (mime == QString("image/x-raw"))
 
380
            {
 
381
                DMetadata metaData(fi.filePath());
 
382
                dims = metaData.getImageDimensions();
 
383
            }
 
384
            else
 
385
            {
 
386
                KFileMetaInfo meta(fi.filePath());
 
387
                if (meta.isValid())
 
388
                {
 
389
                    if (meta.containsGroup("Jpeg EXIF Data"))
 
390
                        dims = meta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
 
391
                    else if (meta.containsGroup("General"))
 
392
                        dims = meta.group("General").item("Dimensions").value().toSize();
 
393
                    else if (meta.containsGroup("Technical"))
 
394
                        dims = meta.group("Technical").item("Dimensions").value().toSize();
 
395
                }
 
396
            }
 
397
        }
 
398
 
 
399
        itemInfo.name             = fi.fileName();
 
400
        itemInfo.folder           = !folder.endsWith("/") ? folder + QString("/") : folder;
 
401
        itemInfo.mime             = mime;
 
402
        itemInfo.mtime            = fi.lastModified().toTime_t();
 
403
        itemInfo.size             = fi.size();
 
404
        itemInfo.width            = dims.width();
 
405
        itemInfo.height           = dims.height();
 
406
        itemInfo.downloaded       = GPItemInfo::DownloadUnknow;
 
407
        itemInfo.readPermissions  = fi.isReadable();
 
408
        itemInfo.writePermissions = fi.isWritable();
 
409
    }
 
410
 
 
411
    return true;
310
412
}
311
413
 
312
 
void UMSCamera::listFolders(const QString& folder,
313
 
                            QStringList& subFolderList)
 
414
void UMSCamera::listFolders(const QString& folder, QStringList& subFolderList)
314
415
{
315
416
    if (m_cancel)
316
417
        return;
328
429
    while ((fi = it.current()) != 0 && !m_cancel)
329
430
    {
330
431
        ++it;
331
 
        
 
432
 
332
433
        if (fi->fileName() == "." || fi->fileName() == "..")
333
434
            continue;
334
435
 
335
 
        QString subfolder = folder + QString(folder.endsWith("/") ? "" : "/")
336
 
                            + fi->fileName();
 
436
        QString subfolder = folder + QString(folder.endsWith("/") ? "" : "/") + fi->fileName();
337
437
        subFolderList.append(subfolder);
338
 
        listFolders(subfolder, subFolderList);        
339
 
    }
340
 
}
341
 
 
342
 
QString UMSCamera::mimeType(const QString& fileext) const
343
 
{
344
 
    QString ext = fileext;
345
 
    
346
 
    // massage known variations of known mimetypes into kde specific ones
347
 
    if (ext == "jpg")
348
 
        ext = "jpeg";
349
 
    else if (ext == "tif")
350
 
        ext = "tiff";
351
 
    
352
 
    if (m_imageFilter.contains(ext))
353
 
    {
354
 
        return "image/" + ext;
355
 
    }
356
 
    else if (m_movieFilter.contains(ext))
357
 
    {
358
 
        return "video/" + ext;
359
 
    }
360
 
    else if (m_audioFilter.contains(ext))
361
 
    {
362
 
        return "audio/" + ext;
363
 
    }
364
 
    else if (m_rawFilter.contains(ext))
365
 
    {
366
 
        return "image/" + ext;
367
 
    }
368
 
    else
369
 
    {
370
 
        return QString();
371
 
    }
372
 
}
 
438
        listFolders(subfolder, subFolderList);
 
439
    }
 
440
}
 
441
 
 
442
bool UMSCamera::cameraSummary(QString& summary)
 
443
{
 
444
    summary = QString(i18n("<b>Mounted Camera</b> driver for USB/IEEE1394 mass storage cameras and "
 
445
                           "Flash disk card readers.<br><br>"));
 
446
 
 
447
    summary.append(i18n("Title: %1<br>"
 
448
                        "Model: %2<br>"
 
449
                        "Port: %3<br>"
 
450
                        "Path: %4<br>")
 
451
                        .arg(title())
 
452
                        .arg(model())
 
453
                        .arg(port())
 
454
                        .arg(path()));
 
455
    return true;
 
456
}
 
457
 
 
458
bool UMSCamera::cameraManual(QString& manual)
 
459
{
 
460
    manual = QString(i18n("For more information about the <b>Mounted Camera</b> driver, "
 
461
                          "please read <b>Supported Digital Still "
 
462
                          "Cameras</b> section in the digiKam manual."));
 
463
    return true;
 
464
}
 
465
 
 
466
bool UMSCamera::cameraAbout(QString& about)
 
467
{
 
468
    about = QString(i18n("The <b>Mounted Camera</b> driver is a simple interface to a camera disk "
 
469
                         "mounted locally on your system.<br><br>"
 
470
                         "It doesn't use libgphoto2 drivers.<br><br>"
 
471
                         "To report any problems with this driver, please contact the digiKam team at:<br><br>"
 
472
                         "http://www.digikam.org/?q=contact"));
 
473
    return true;
 
474
}
 
475
 
 
476
}  // namespace Digikam