public void SaveData(Context ctx) { KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions); using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions)) { DatabaseFormat.Save(KpDatabase, trans.OpenFile()); trans.CommitWrite(); } }
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task <MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish) : base(activity, finish) { _app = app; _ioc = ioc; _databaseData = databaseData; _compositeKey = compositeKey; _keyfileOrProvider = keyfileOrProvider; _rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile); }
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish) : base(finish) { _app = app; _ioc = ioc; _databaseData = databaseData; _compositeKey = compositeKey; _keyfileOrProvider = keyfileOrProvider; _rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile); }
public static void Copy(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc, IKp2aApp app) { IFileStorage sourceStorage = app.GetFileStorage(sourceIoc, false); //don't cache source. file won't be used ever again IFileStorage targetStorage = app.GetFileStorage(targetIoc); using ( var writeTransaction = targetStorage.OpenWriteTransaction(targetIoc, app.GetBooleanPreference( PreferenceKey.UseFileTransactions))) { using (var writeStream = writeTransaction.OpenFile()) { sourceStorage.OpenFileForRead(sourceIoc).CopyTo(writeStream); } writeTransaction.CommitWrite(); } }
public override void Run() { if (!_dontSave) { try { if (_db.CanWrite == false) { //this should only happen if there is a problem in the UI so that the user sees an edit interface. Finish(false, "Cannot save changes. File is read-only!"); return; } string message = _app.GetResourceString(UiStringKey.saving_database); if (ShowDatabaseIocInStatus) { message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")"; } StatusLogger.UpdateMessage(message); IOConnectionInfo ioc = _db.Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (_streamForOrigFile == null) { if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); return; } } if ( (_streamForOrigFile != null) || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) || //first try to use the fast change detection (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare: ) { //ask user... _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion, UiStringKey.YesSynchronize, UiStringKey.NoOverwrite, //yes = sync (sender, args) => { Action runHandler = () => { //note: when synced, the file might be downloaded once again from the server. Caching the data //in the hashing function would solve this but increases complexity. I currently assume the files are //small. MergeIn(fileStorage, ioc); PerformSaveWithoutCheck(fileStorage, ioc); _db.UpdateGlobals(); Finish(true); }; RunInWorkerThread(runHandler); }, //no = overwrite (sender, args) => { RunInWorkerThread(() => { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); }); }, //cancel (sender, args) => { RunInWorkerThread(() => Finish(false)); }, _ctx ); } else { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); } } catch (Exception e) { /* TODO KPDesktop: * catch(Exception exSave) * { * MessageService.ShowSaveWarning(pd.IOConnectionInfo, exSave, true); * bSuccess = false; * } */ Kp2aLog.LogUnexpectedError(e); Finish(false, e.Message); return; } } else { Finish(true); } }
public override void Run() { if (!_dontSave) { try { if (_db.CanWrite == false) { //this should only happen if there is a problem in the UI so that the user sees an edit interface. Finish(false, "Cannot save changes. File is read-only!"); return; } string message = _app.GetResourceString(UiStringKey.saving_database); if (ShowDatabaseIocInStatus) { message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")"; } StatusLogger.UpdateMessage(message); IOConnectionInfo ioc = _db.Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (_streamForOrigFile == null) { if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); return; } } bool hasStreamForOrigFile = (_streamForOrigFile != null); bool hasChangeFast = hasStreamForOrigFile || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion); //first try to use the fast change detection; bool hasHashChanged = hasChangeFast || (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed); //if that fails, hash the file and compare: if (hasHashChanged) { Kp2aLog.Log("Conflict. " + hasStreamForOrigFile + " " + hasChangeFast + " " + hasHashChanged); bool alwaysMerge = (PreferenceManager.GetDefaultSharedPreferences(Application.Context) .GetBoolean("AlwaysMergeOnConflict", false)); if (alwaysMerge) { MergeAndFinish(fileStorage, ioc); } else { //ask user... _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion, UiStringKey.YesSynchronize, UiStringKey.NoOverwrite, //yes = sync (sender, args) => { Action runHandler = () => { MergeAndFinish(fileStorage, ioc); }; RunInWorkerThread(runHandler); }, //no = overwrite (sender, args) => { RunInWorkerThread(() => { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); }); }, //cancel (sender, args) => { RunInWorkerThread(() => Finish(false)); }, _ctx ); } } else { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); } } catch (Exception e) { /* TODO KPDesktop: * catch(Exception exSave) * { * MessageService.ShowSaveWarning(pd.IOConnectionInfo, exSave, true); * bSuccess = false; * } */ Kp2aLog.LogUnexpectedError(e); Finish(false, e.Message); return; } } else { Finish(true); } }
public override void Run() { StatusLogger.UpdateMessage(UiStringKey.exporting_database); var pd = _app.CurrentDb.KpDatabase; PwExportInfo pwInfo = new PwExportInfo(pd.RootGroup, pd, true); try { var fileStorage = _app.GetFileStorage(_targetIoc); if (fileStorage is IOfflineSwitchable) { ((IOfflineSwitchable)fileStorage).IsOffline = false; } using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions))) { Stream sOut = writeTransaction.OpenFile(); _fileFormat.Export(pwInfo, sOut, new NullStatusLogger()); if (sOut != null) { sOut.Close(); } writeTransaction.CommitWrite(); } if (fileStorage is IOfflineSwitchable) { ((IOfflineSwitchable)fileStorage).IsOffline = App.Kp2a.OfflineMode; } Finish(true); } catch (Exception ex) { Finish(false, ex.Message); } }
public override void Run() { try { IOConnectionInfo ioc = _app.GetDb().Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (!(fileStorage is CachingFileStorage)) { throw new Exception("Cannot sync a non-cached database!"); } StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase); CachingFileStorage cachingFileStorage = (CachingFileStorage)fileStorage; //download file from remote location and calculate hash: StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile)); string hash; MemoryStream remoteData; try { remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash); } catch (FileNotFoundException) { StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile)); cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); return; } //check if remote file was modified: if (cachingFileStorage.GetBaseVersionHash(ioc) != hash) { //remote file is modified if (cachingFileStorage.HasLocalChanges(ioc)) { //conflict! need to merge _saveDb = new SaveDb(_context, _app, new ActionOnFinish((success, result) => { if (!success) { Finish(false, result); } else { Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); } _saveDb = null; }), false, remoteData); _saveDb.Run(); _app.GetDb().MarkAllGroupsAsDirty(); } else { //only the remote file was modified -> reload database. //note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.) _app.TriggerReload(_context); Finish(true); } } else { //remote file is unmodified if (cachingFileStorage.HasLocalChanges(ioc)) { //but we have local changes -> upload: StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile)); cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)); StatusLogger.UpdateSubMessage(""); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); } else { //files are in sync: just set the result Finish(true, _app.GetResourceString(UiStringKey.FilesInSync)); } } } catch (Exception e) { Finish(false, e.Message); } }