From da7795437be9ce9bf49378641b3e5faa708024cb Mon Sep 17 00:00:00 2001 From: Juan Carlos Cornejo Date: Thu, 3 Nov 2011 20:47:04 -0400 Subject: [PATCH] Major fixes in this version. Apparently there were a lot of bugs in comparing files between the server. Now it is more reasonable. Also, less use of the hardisk because now I implemented a QFileSystemWatch instance. This is much better and lets me know of file changes. Though, there is still a strain on the HD due to the constant SQLite access that I use. I can't figure out a nice way to find out what files were added (removed will be fore later) without listing the entire directory and comparing against the DB. --- SyncWindow.cpp | 220 ++++++++++++++++++++++++++++++++---------- SyncWindow.h | 14 ++- owncloud_sync.desktop | 11 +++ owncloud_sync.png | Bin 0 -> 2501 bytes owncloud_sync.pro | 17 ++++ 5 files changed, 209 insertions(+), 53 deletions(-) create mode 100644 owncloud_sync.desktop create mode 100644 owncloud_sync.png diff --git a/SyncWindow.cpp b/SyncWindow.cpp index 3f75d6ee6..8fa80b1bf 100644 --- a/SyncWindow.cpp +++ b/SyncWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include SyncWindow::SyncWindow(QWidget *parent) : QMainWindow(parent), @@ -29,8 +30,16 @@ SyncWindow::SyncWindow(QWidget *parent) : connect(mSystemTray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this,SLOT(systemTrayActivated(QSystemTrayIcon::ActivationReason))); + // Create a QWebDAV instance mWebdav = new QWebDAV(); + // Create a File System Watcher + mFileWatcher = new QFileSystemWatcher(this); + connect(mFileWatcher,SIGNAL(fileChanged(QString)), + this, SLOT(localFileChanged(QString))); + connect(mFileWatcher,SIGNAL(directoryChanged(QString)), + this, SLOT(localDirectoryChanged(QString))); + // Connect to QWebDAV signals connect(mWebdav,SIGNAL(directoryListingReady(QList)), this, SLOT(processDirectoryListing(QList))); @@ -128,8 +137,34 @@ void SyncWindow::timeToSync() mBusy = true; ui->textBrowser->append("Time to sync!"); - // First scan the local directory and find any changes - scanLocalDirectory(mSyncDirectory); + + // If this is the first run, scan the directory, otherwise just wait + // for the watcher to update us :) + if(mIsFirstRun) { + scanLocalDirectory(mSyncDirectory); + } + mIsFirstRun = false; + + if ( mScanDirectoriesSet.size() != 0 ) { + while( mScanDirectories.size() > 0 ) { + QString relativeName = mScanDirectories.dequeue(); + QString name(relativeName); + name.replace("_sssspace_"," "); + scanLocalDirectoryForNewFiles(name); + mScanDirectoriesSet.remove(relativeName); + } + } + + // List all the watched files for now + /* + QStringList list = mFileWatcher->files(); + for(int i = 0; i < list.size(); i++ ) { + qDebug() << "Watching: " << list[i]; + } + list = mFileWatcher->directories(); + for(int i = 0; i < list.size(); i++ ) { + qDebug() << "Watching: " << list[i]; + } */ // Then scan the base directory of the WebDAV server mWebdav->dirList("/"); @@ -156,8 +191,8 @@ void SyncWindow::processDirectoryListing(QList fileInfo) //ui->textBrowser->append("File " + fileInfo[i].fileName + // " exists. Comparing!"); QString updateStatement = - QString("UPDATE local_files SET file_size=%1," - "last_modified=%2 where file_name='%3") + QString("UPDATE server_files SET file_size='%1'," + "last_modified='%2' where file_name='%3'") .arg(fileInfo[i].size) .arg(fileInfo[i].lastModified) .arg(fileInfo[i].fileName); @@ -225,50 +260,67 @@ void SyncWindow::scanLocalDirectory( QString dirPath) if( name == "." || name == ".." ) { continue; } - QString relativeName(dirPath + QString("/") + name); - relativeName.replace(mSyncDirectory,""); + //qDebug() << "Relative Path: " << relativeName; - QFileInfo file(dirPath + "/" + name); + processLocalFile(dirPath + "/" + name); // Check if it is a directory, and if so, process it - if ( file.isDir() ) { - type = "collection"; - append = "/"; - } else { - type = "file"; - append = ""; - } - - // Check against the database - QSqlQuery query = queryDBFileInfo(relativeName,"local_files"); - if (query.next() ) { // We already knew about this file. Compare. - QString updateStatement = - QString("UPDATE local_files SET file_size=%1," - "last_modified=%2 where file_name='%3'") - .arg(file.size()) - .arg(file.lastModified().toUTC() - .toMSecsSinceEpoch()) - .arg(relativeName); - //qDebug() << "Query: " << updateStatement; - query.exec(updateStatement); - } else { // We did not know about this file, add - QString addStatement = QString("INSERT INTO local_files (file_name," - "file_size,file_type,last_modified) " - "values('%1','%2','%3','%4');") - .arg(relativeName+append).arg(file.size()) - .arg(type) - .arg(file.lastModified().toUTC().toMSecsSinceEpoch()); - //qDebug() << "Query: " << addStatement; - query.exec(addStatement); - } - //qDebug() << "Processing: " << mSyncDirectory + relativeName << " Size: " << file.size(); - - if ( file.isDir() ) { - scanLocalDirectory(file.absoluteFilePath() ); - } } } +void SyncWindow::processLocalFile(QString name) +{ + QFileInfo file( name ); + QString type; + QString append; + // Check if it is a directory, and if so, process it + if ( file.isDir() ) { + type = "collection"; + append = "/"; + } else { + type = "file"; + append = ""; + } + + // Add to the watcher + mFileWatcher->addPath(name+append); + updateDBLocalFile(name + append, + file.size(),file.lastModified().toUTC() + .toMSecsSinceEpoch(),type); + + if ( file.isDir() ) { + scanLocalDirectory(file.absoluteFilePath() ); + } +} + +void SyncWindow::updateDBLocalFile(QString name, qint64 size, qint64 last, + QString type ) +{ + // Get the relative name of the file + name.replace(mSyncDirectory,""); + // Check against the database + QSqlQuery query = queryDBFileInfo(name,"local_files"); + if (query.next() ) { // We already knew about this file. Update info. + QString updateStatement = + QString("UPDATE local_files SET file_size='%1'," + "last_modified='%2' where file_name='%3'") + .arg(size) + .arg(last) + .arg(name); + //qDebug() << "Query: " << updateStatement; + query.exec(updateStatement); + } else { // We did not know about this file, add + QString addStatement = QString("INSERT INTO local_files (file_name," + "file_size,file_type,last_modified) " + "values('%1','%2','%3','%4');") + .arg(name).arg(size).arg(type).arg(last); + //qDebug() << "Query: " << addStatement; + query.exec(addStatement); + } + //qDebug() << "Processing: " << mSyncDirectory + relativeName << " Size: " + // << file.size(); +} + QSqlQuery SyncWindow::queryDBFileInfo(QString fileName, QString table) { QSqlQuery query; @@ -341,6 +393,7 @@ void SyncWindow::syncFiles() //uploads.append(localName); //uploadsSizes.append(localSize); mTotalToUpload +=localSize; + //qDebug() << "File " << localName << " is newer than server!"; } //qDebug() << "UPLOAD: " << localName; } else if ( serverModifiedTime > localModifiedTime && @@ -475,6 +528,7 @@ void SyncWindow::upload( FileInfo fileInfo) void SyncWindow::updateDBDownload(QString name) { + // This seems redundant, a little, really. QString fileName = mSyncDirectory+name; QFileInfo file(fileName); @@ -482,8 +536,9 @@ void SyncWindow::updateDBDownload(QString name) QSqlQuery query = queryDBFileInfo(name,"local_files"); if (query.next() ) { // We already knew about this file. Update. QString updateStatement = - QString("UPDATE local_files SET file_size=%1," - "last_modified=%2,last_sync=%3 where file_name='%4").arg(file.size()) + QString("UPDATE local_files SET file_size='%1'," + "last_modified='%2',last_sync='%3' where file_name='%4'") + .arg(file.size()) .arg(file.lastModified().toUTC() .toMSecsSinceEpoch()) .arg(file.lastModified().toUTC() @@ -501,6 +556,7 @@ void SyncWindow::updateDBDownload(QString name) query.exec(addStatement); } ui->textBrowser->append("Downloaded file: " + name ); + //qDebug() << "Did this get called?"; mTotalTransfered += mCurrentFileSize; } @@ -515,29 +571,29 @@ void SyncWindow::updateDBUpload(QString name) QSqlQuery query = queryDBFileInfo(name,"server_files"); if (query.next() ) { // We already knew about this file. Update. QString updateStatement = - QString("UPDATE server_files SET file_size=%1," - "last_modified=%2 where file_name='%3") + QString("UPDATE server_files SET file_size='%1'," + "last_modified='%2' where file_name='%3'") .arg(file.size()) .arg(time).arg(name); //qDebug() << "Query: " << updateStatement; query.exec(updateStatement); updateStatement = - QString("UPDATE local_files SET last_sync=%1 where file_name='%2'") + QString("UPDATE local_files SET last_sync='%1'" + "where file_name='%2'") .arg(time).arg(name); query.exec(updateStatement); //qDebug() << "Query: " << updateStatement; } else { // We did not know about this file, add QString addStatement = QString("INSERT INTO server_files (file_name," "file_size,file_type,last_modified) " - "values('%1','%2','%3','%4','%5');") + "values('%1','%2','%3','%4');") .arg(name).arg(file.size()) .arg("file") - .arg(time) .arg(time); query.exec(addStatement); QString updateStatement = - QString("UPDATE local_files SET file_size=%1," - "last_modified=%2,last_sync=%3 where file_name='%4") + QString("UPDATE local_files SET file_size='%1'," + "last_modified='%2',last_sync='%3' where file_name='%4'") .arg(file.size()).arg(time).arg(time).arg(name); query.exec(updateStatement); } @@ -679,9 +735,71 @@ void SyncWindow::initialize() // Initialize WebDAV mWebdav->initialize(mHost,mUsername,mPassword,"/files/webdav.php"); + mFileWatcher->addPath(mSyncDirectory+"/"); + // Synchronize then start the timer + mIsFirstRun = true; timeToSync(); mSyncTimer = new QTimer(this); connect(mSyncTimer, SIGNAL(timeout()), this, SLOT(timeToSync())); mSyncTimer->start(mUpdateTime*1000); } + +void SyncWindow::localDirectoryChanged(QString name) +{ + // Since we don't want to be scanning the directories every single + // time a file is changed (since temporary files could be the cause) + // instead we'll add them to a list and have a separate timer + // randomly go through them + QString relativeName(name); + relativeName.replace(mSyncDirectory,""); + // Replace spaces because it may confuse QSet + relativeName.replace(" ","_sssspace_"); + if( !mScanDirectoriesSet.contains(relativeName) ) { + // Add to the list + mScanDirectoriesSet.insert(relativeName); + mScanDirectories.enqueue(relativeName); + } +} + +void SyncWindow::localFileChanged(QString name) +{ + QFileInfo info(name); + name.replace(mSyncDirectory,""); + //qDebug() << "File " << name << " changed."; + if( info.exists() ) { // Ok, file did not get deleted + updateDBLocalFile(name,info.size(), + info.lastModified().toUTC().toMSecsSinceEpoch(),"file"); + } else { // File got deleted (or moved!) I can't do anything for now :( + + } +} + +void SyncWindow::scanLocalDirectoryForNewFiles(QString path) +{ + //qDebug() << "Scanning local directory: " << path; + QDir dir(mSyncDirectory+path); + QStringList list = dir.entryList(); + for( int i = 0; i < list.size(); i++ ) { + + // Skip current and previous directory + QString name = list.at(i); + if( name == "." || name == ".." ) { + continue; + } + + QSqlQuery query; + query.exec(QString("SELECT * from local_files where file_name='%1'") + .arg(path+list[i])); + if( !query.next() ) { // Ok, this file does not exist. It might be a + // directory, however, so let's check again! + query.exec(QString("SELECT * from local_files where " + "file_name='%1/'").arg(path+list[i])); + if( !query.next() ) { // Definitely does not exist! Good! + // File really doesn't exist!!! + processLocalFile(mSyncDirectory+path+list[i]); + } + } + //QString name = pathi+"/"+list[i]; + } +} diff --git a/SyncWindow.h b/SyncWindow.h index 43db4b750..eb10f1cd8 100644 --- a/SyncWindow.h +++ b/SyncWindow.h @@ -5,11 +5,12 @@ #include "QWebDAV.h" #include #include -#include #include #include +#include class QTimer; +class QFileSystemWatcher; namespace Ui { class SyncWindow; @@ -45,7 +46,7 @@ private: QString mPassword; QString mUsername; QTimer *mSyncTimer; - QTimer *mStatusTimer; + QTimer *mCheckDirsTimer; QQueue mUploadingFiles; QQueue mDownloadingFiles; //QHash mUploadingFiles; @@ -64,7 +65,12 @@ private: qint64 mUpdateTime; QIcon mDefaultIcon; QIcon mSyncIcon; + QFileSystemWatcher *mFileWatcher; + bool mIsFirstRun; + QSet mScanDirectoriesSet; + QQueue mScanDirectories; + void updateDBLocalFile(QString name,qint64 size,qint64 last,QString type); void scanLocalDirectory(QString dirPath); QSqlQuery queryDBFileInfo(QString fileName, QString table); QSqlQuery queryDBAllFiles(QString table); @@ -77,6 +83,8 @@ private: void initialize(); void readConfigFromDB(); void saveConfigToDB(); + void scanLocalDirectoryForNewFiles(QString name); + void processLocalFile(QString name); public slots: void processDirectoryListing(QList fileInfo); @@ -87,6 +95,8 @@ public slots: void transferProgress(qint64 current,qint64 total); void systemTrayActivated(QSystemTrayIcon::ActivationReason reason); void saveButtonClicked(); + void localFileChanged(QString name); + void localDirectoryChanged(QString name); }; #endif // SYNCWINDOW_H diff --git a/owncloud_sync.desktop b/owncloud_sync.desktop new file mode 100644 index 000000000..d6da1e987 --- /dev/null +++ b/owncloud_sync.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=1.0 +Type=Application +Terminal=false +Name=Owncloud Sync +Exec=/opt/owncloud_sync/bin/owncloud_sync +Icon=owncloud_sync +X-Window-Icon= +X-HildonDesk-ShowInToolbar=true +X-Osso-Type=application/x-executable diff --git a/owncloud_sync.png b/owncloud_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..0148bfb39c42be74d9e2aa90b3309039c63ba025 GIT binary patch literal 2501 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 P00000NkvXXu0mjfJKVA* literal 0 HcmV?d00001 diff --git a/owncloud_sync.pro b/owncloud_sync.pro index e3cdc9e0c..4d2c8e8e0 100644 --- a/owncloud_sync.pro +++ b/owncloud_sync.pro @@ -23,3 +23,20 @@ INCLUDEPATH += qwebdav/ RESOURCES += \ owncloud_sync.qrc + +unix:!symbian:!maemo5:isEmpty(MEEGO_VERSION_MAJOR) { + target.path = /opt/owncloud_sync/bin + INSTALLS += target +} + +unix:!symbian:!maemo5:isEmpty(MEEGO_VERSION_MAJOR) { + desktopfile.files = $${TARGET}.desktop + desktopfile.path = /usr/share/applications + INSTALLS += desktopfile +} + +unix:!symbian:!maemo5:isEmpty(MEEGO_VERSION_MAJOR) { + icon.files = owncloud_sync.png + icon.path = /usr/share/icons/hicolor/64x64/apps + INSTALLS += icon +}