diff --git a/assets/delete.kdb b/assets/delete.kdb
new file mode 100644
index 000000000..876547bc5
Binary files /dev/null and b/assets/delete.kdb differ
diff --git a/res/layout/create_group.xml b/res/layout/create_group.xml
index 893a8f9e8..f78a41914 100644
--- a/res/layout/create_group.xml
+++ b/res/layout/create_group.xml
@@ -23,6 +23,7 @@
-
\ No newline at end of file
+
diff --git a/src/com/keepassdroid/Database.java b/src/com/keepassdroid/Database.java
index ced70179f..60f29e535 100644
--- a/src/com/keepassdroid/Database.java
+++ b/src/com/keepassdroid/Database.java
@@ -107,104 +107,6 @@ public class Database {
return searchHelper.search(this, str);
}
- public void NewGroup(String name, PwGroup parent) throws PwManagerOutputException, IOException {
- // Generate new group
- PwGroup group = mPM.newGroup(name, parent);
-
- // Commit to disk
- try {
- SaveData();
- } catch (PwManagerOutputException e) {
- mPM.removeGroup(group);
- throw e;
- } catch (IOException e) {
- mPM.removeGroup(group);
- throw e;
- }
-
- // Mark parent group dirty
- gDirty.put(parent, new WeakReference(parent));
-
- // Add group to global list
- gGroups.put(group.groupId, new WeakReference(group));
-
- }
-
- public void NewEntry(PwEntry entry) throws IOException, PwManagerOutputException {
- PwGroup parent = entry.parent;
-
- // Add entry to group
- parent.childEntries.add(entry);
-
- // Add entry to PwManager
- mPM.entries.add(entry);
-
- // Commit to disk
- try {
- SaveData();
- } catch (PwManagerOutputException e) {
- UndoNewEntry(entry);
- throw e;
- } catch (IOException e) {
- UndoNewEntry(entry);
- throw e;
- }
-
- // Mark parent group dirty
- gDirty.put(parent, new WeakReference(parent));
-
- // Add entry to global
- gEntries.put(Types.bytestoUUID(entry.uuid), new WeakReference(entry));
-
- // Add entry to search index
- searchHelper.insertEntry(entry);
- }
-
- public void UndoNewEntry(PwEntry entry) {
- // Remove from group
- entry.parent.childEntries.removeElement(entry);
-
- // Remove from manager
- mPM.entries.removeElement(entry);
- }
-
- public void UpdateEntry(PwEntry oldE, PwEntry newE) throws IOException, PwManagerOutputException {
-
- // Keep backup of original values in case save fails
- PwEntry backup = new PwEntry(oldE);
-
- // Update entry with new values
- oldE.assign(newE);
-
- try {
- SaveData();
- } catch (PwManagerOutputException e) {
- UndoUpdateEntry(oldE, backup);
- throw e;
- } catch (IOException e) {
- UndoUpdateEntry(oldE, backup);
- throw e;
- }
-
- // Mark group dirty if title changes
- if ( ! oldE.title.equals(newE.title) ) {
- PwGroup parent = oldE.parent;
- if ( parent != null ) {
- // Mark parent group dirty
- gDirty.put(parent, new WeakReference(parent));
- }
- }
-
- // Update search index
- searchHelper.updateEntry(oldE);
-
- }
-
- public void UndoUpdateEntry(PwEntry old, PwEntry backup) {
- // If we fail to save, back out changes to global structure
- old.assign(backup);
- }
-
public void SaveData() throws IOException, PwManagerOutputException {
SaveData(mFilename);
}
diff --git a/src/com/keepassdroid/EntryActivity.java b/src/com/keepassdroid/EntryActivity.java
index ba42744ee..d8eb58a06 100644
--- a/src/com/keepassdroid/EntryActivity.java
+++ b/src/com/keepassdroid/EntryActivity.java
@@ -55,7 +55,7 @@ public class EntryActivity extends LockingActivity {
private static final int MENU_COPY_PASS = Menu.FIRST + 3;
private static final int MENU_LOCK = Menu.FIRST + 4;
- private static final long CLIP_CLEAR_TIME = 300 * 1000;
+ private static final long CLIP_CLEAR_TIME = 5 * 60 * 1000;
public static void Launch(Activity act, PwEntry pw, int pos) {
Intent i = new Intent(act, EntryActivity.class);
diff --git a/src/com/keepassdroid/EntryEditActivity.java b/src/com/keepassdroid/EntryEditActivity.java
index 9526cd2f4..04e1abd85 100644
--- a/src/com/keepassdroid/EntryEditActivity.java
+++ b/src/com/keepassdroid/EntryEditActivity.java
@@ -29,7 +29,6 @@ import org.phoneid.keepassj2me.PwGroup;
import org.phoneid.keepassj2me.Types;
import android.app.Activity;
-import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -43,6 +42,8 @@ import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
+import com.keepassdroid.database.AddEntry;
+import com.keepassdroid.database.UpdateEntry;
public class EntryEditActivity extends LockingActivity {
public static final String KEY_ENTRY = "entry";
@@ -53,7 +54,6 @@ public class EntryEditActivity extends LockingActivity {
private PwEntry mEntry;
private boolean mShowPassword = false;
private boolean mIsNew;
- private ProgressDialog mPd;
public static void Launch(Activity act, PwEntry pw) {
Intent i = new Intent(act, EntryEditActivity.class);
@@ -165,11 +165,15 @@ public class EntryEditActivity extends LockingActivity {
} else {
setResult(KeePass.EXIT_REFRESH_TITLE);
}
-
- mPd = ProgressDialog.show(EntryEditActivity.this, "Working...", "Saving database", true, false);
- Thread bkgStore = new Thread(new BackgroundUpdateEntry(mEntry, newEntry));
- bkgStore.start();
-
+
+ Runnable task;
+ if ( mIsNew ) {
+ task = new AddEntry(KeePass.db, act, newEntry, new Handler());
+ } else {
+ task = new UpdateEntry(KeePass.db, act, mEntry, newEntry, new Handler());
+ }
+ ProgressTask pt = new ProgressTask(act, task, act.new AfterSave());
+ pt.run();
}
});
@@ -248,46 +252,13 @@ public class EntryEditActivity extends LockingActivity {
tv.setText(text);
}
- private final Handler uiHandler = new Handler();
-
private final class AfterSave implements Runnable {
@Override
public void run() {
- mPd.dismiss();
finish();
}
}
-
- private final class BackgroundUpdateEntry implements Runnable {
-
- private final PwEntry mOld;
- private final PwEntry mNew;
-
- public BackgroundUpdateEntry(PwEntry oldE, PwEntry newE) {
- mOld = oldE;
- mNew = newE;
- }
-
- @Override
- public void run() {
- try {
- if ( mIsNew ) {
- KeePass.db.NewEntry(mNew);
- } else {
- KeePass.db.UpdateEntry(mOld, mNew);
- }
-
- uiHandler.post(new AfterSave());
- } catch (Exception e) {
- uiHandler.post(new UIToastTask(EntryEditActivity.this, "Failed to store database."));
- mPd.dismiss();
- setResult(KeePass.EXIT_NORMAL);
- return;
- }
- }
-
- }
}
diff --git a/src/com/keepassdroid/GroupActivity.java b/src/com/keepassdroid/GroupActivity.java
index 2366aa104..19f1c4106 100644
--- a/src/com/keepassdroid/GroupActivity.java
+++ b/src/com/keepassdroid/GroupActivity.java
@@ -25,7 +25,6 @@ import org.phoneid.keepassj2me.PwGroup;
import android.app.Activity;
import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
@@ -39,6 +38,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import com.android.keepass.KeePass;
import com.android.keepass.R;
+import com.keepassdroid.database.AddGroup;
public class GroupActivity extends GroupBaseActivity {
@@ -47,8 +47,6 @@ public class GroupActivity extends GroupBaseActivity {
public static final int ADD_GROUP_ONLY = 1;
public static final int FULL = 2;
- private ProgressDialog mPd;
-
public static void Launch(Activity act, PwGroup group, int mode) {
Intent i = new Intent(act, GroupActivity.class);
@@ -160,9 +158,10 @@ public class GroupActivity extends GroupBaseActivity {
String res = mDialog.getResponse();
if ( ! mDialog.canceled() && res.length() > 0 ) {
- mPd = ProgressDialog.show(GroupActivity.this, "Working...", "Saving database", true, false);
- Thread bkgStore = new Thread(new BackgroundAddGroup(res, mGroup));
- bkgStore.start();
+ GroupActivity act = GroupActivity.this;
+ AddGroup task = new AddGroup(KeePass.db, act, res, mGroup, new Handler(), false);
+ ProgressTask pt = new ProgressTask(act, task, act.new RefreshTask());
+ pt.run();
}
}
@@ -173,48 +172,5 @@ public class GroupActivity extends GroupBaseActivity {
}
}
-
- private final Handler uiHandler = new Handler();
-
- /** Task to be run after the database is saved in the UI thread
- * @author Brian Pellin
- *
- */
- private final class AfterSave implements Runnable {
-
- @Override
- public void run() {
- mPd.dismiss();
- refreshIfDirty();
- }
-
- }
-
- /** Handler storing the database in a separate thread
- * @author Brian Pellin
- *
- */
- private final class BackgroundAddGroup implements Runnable {
-
- private final String mName;
- private final PwGroup mParent;
-
- public BackgroundAddGroup(String name, PwGroup parent) {
- mName = name;
- mParent = parent;
- }
-
- @Override
- public void run() {
- try {
- KeePass.db.NewGroup(mName, mParent);
- uiHandler.post(new AfterSave());
- } catch (Exception e) {
- uiHandler.post(new UIToastTask(GroupActivity.this, R.string.error_could_not_create_group));
- mPd.dismiss();
- }
- }
-
- }
}
diff --git a/src/com/keepassdroid/GroupBaseActivity.java b/src/com/keepassdroid/GroupBaseActivity.java
index 420d08718..9afbf2719 100644
--- a/src/com/keepassdroid/GroupBaseActivity.java
+++ b/src/com/keepassdroid/GroupBaseActivity.java
@@ -31,6 +31,7 @@ import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
@@ -61,13 +62,6 @@ public abstract class GroupBaseActivity extends LockingListActivity {
refreshIfDirty();
}
- public class RefreshTask implements Runnable {
- @Override
- public void run() {
- refreshIfDirty();
- }
- }
-
public void refreshIfDirty() {
if ( KeePass.db.gDirty.get(mGroup) != null ) {
KeePass.db.gDirty.remove(mGroup);
@@ -157,4 +151,27 @@ public abstract class GroupBaseActivity extends LockingListActivity {
return super.onOptionsItemSelected(item);
}
+ public class RefreshTask implements Runnable {
+ @Override
+ public void run() {
+ refreshIfDirty();
+ }
+ }
+
+ public class FatalError implements Runnable {
+ String mMsg;
+
+ public FatalError(String msg) {
+ mMsg = msg;
+ }
+
+ @Override
+ public void run() {
+ Toast.makeText(GroupBaseActivity.this, "Unrecoverable error: " + mMsg, Toast.LENGTH_LONG);
+ KeePass.db.shutdown = true;
+ finish();
+ }
+
+ }
+
}
diff --git a/src/com/keepassdroid/PasswordActivity.java b/src/com/keepassdroid/PasswordActivity.java
index 29ca51eed..61ee3a24e 100644
--- a/src/com/keepassdroid/PasswordActivity.java
+++ b/src/com/keepassdroid/PasswordActivity.java
@@ -170,10 +170,12 @@ public class PasswordActivity extends Activity {
sendBroadcast(new Intent(TimeoutIntents.START));
}
+ /*
private void errorMessage(CharSequence text)
{
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
+ */
private void errorMessage(int resId)
{
diff --git a/src/com/keepassdroid/PwEntryView.java b/src/com/keepassdroid/PwEntryView.java
index d20b0cbf0..5142aee54 100644
--- a/src/com/keepassdroid/PwEntryView.java
+++ b/src/com/keepassdroid/PwEntryView.java
@@ -21,7 +21,7 @@ package com.keepassdroid;
import org.phoneid.keepassj2me.PwEntry;
-import android.app.Activity;
+import android.os.Handler;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
@@ -29,11 +29,13 @@ import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.TextView;
+import com.android.keepass.KeePass;
import com.android.keepass.R;
+import com.keepassdroid.database.DeleteEntry;
public class PwEntryView extends ClickView {
- private Activity mAct;
+ private GroupBaseActivity mAct;
private PwEntry mPw;
private TextView mTv;
private int mPos;
@@ -41,7 +43,7 @@ public class PwEntryView extends ClickView {
private static final int MENU_EDIT = Menu.FIRST;
private static final int MENU_DELETE = Menu.FIRST + 1;
- public PwEntryView(Activity act, PwEntry pw, int pos) {
+ public PwEntryView(GroupBaseActivity act, PwEntry pw, int pos) {
super(act);
mAct = act;
mPw = pw;
@@ -70,11 +72,18 @@ public class PwEntryView extends ClickView {
EntryActivity.Launch(mAct, mPw, mPos);
}
+
+ private void deleteEntry() {
+ DeleteEntry task = new DeleteEntry(KeePass.db, mPw, mAct, new Handler());
+ ProgressTask pt = new ProgressTask(mAct, task, mAct.new RefreshTask());
+ pt.run();
+
+ }
@Override
public void onCreateMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
menu.add(0, MENU_EDIT, 0, R.string.menu_edit);
- //menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
+ menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
}
@Override
@@ -85,6 +94,10 @@ public class PwEntryView extends ClickView {
launchEntry();
return true;
+ case MENU_DELETE:
+ deleteEntry();
+ return true;
+
default:
return false;
}
diff --git a/src/com/keepassdroid/PwGroupView.java b/src/com/keepassdroid/PwGroupView.java
index 6228824b0..f08f0c1fc 100644
--- a/src/com/keepassdroid/PwGroupView.java
+++ b/src/com/keepassdroid/PwGroupView.java
@@ -69,8 +69,8 @@ public class PwGroupView extends ClickView {
@Override
public void onCreateMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
menu.add(0, MENU_OPEN, 0, R.string.menu_open);
+ menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
// TODO: Re-enable need to address entries and last group issue
- //menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
//menu.add(0, MENU_RENAME, 0, R.string.menu_rename);
}
diff --git a/src/com/keepassdroid/database/AddEntry.java b/src/com/keepassdroid/database/AddEntry.java
new file mode 100644
index 000000000..4bfbd71bd
--- /dev/null
+++ b/src/com/keepassdroid/database/AddEntry.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
+package com.keepassdroid.database;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.phoneid.keepassj2me.PwEntry;
+import org.phoneid.keepassj2me.PwGroup;
+import org.phoneid.keepassj2me.Types;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.keepassdroid.Database;
+import com.keepassdroid.UIToastTask;
+import com.keepassdroid.keepasslib.PwManagerOutputException;
+
+public class AddEntry implements Runnable {
+ private Database mDb;
+ private Context mCtx;
+ private PwEntry mEntry;
+ private Handler mHandler;
+
+ public AddEntry(Database db, Context ctx, PwEntry entry, Handler handler) {
+ mDb = db;
+ mCtx = ctx;
+ mEntry = entry;
+ mHandler = handler;
+ }
+
+ @Override
+ public void run() {
+ PwGroup parent = mEntry.parent;
+
+ // Add entry to group
+ parent.childEntries.add(mEntry);
+
+ // Add entry to PwManager
+ mDb.mPM.entries.add(mEntry);
+
+ // Commit to disk
+ try {
+ mDb.SaveData();
+ } catch (PwManagerOutputException e) {
+ undoNewEntry(mEntry);
+ mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
+ } catch (IOException e) {
+ undoNewEntry(mEntry);
+ mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
+ }
+
+ // Mark parent group dirty
+ mDb.gDirty.put(parent, new WeakReference(parent));
+
+ // Add entry to global
+ mDb.gEntries.put(Types.bytestoUUID(mEntry.uuid), new WeakReference(mEntry));
+
+ // Add entry to search index
+ mDb.searchHelper.insertEntry(mEntry);
+ }
+
+ private void undoNewEntry(PwEntry entry) {
+ // Remove from group
+ entry.parent.childEntries.removeElement(entry);
+
+ // Remove from manager
+ mDb.mPM.entries.removeElement(entry);
+ }
+
+}
diff --git a/src/com/keepassdroid/database/AddGroup.java b/src/com/keepassdroid/database/AddGroup.java
new file mode 100644
index 000000000..0596f91f3
--- /dev/null
+++ b/src/com/keepassdroid/database/AddGroup.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
+package com.keepassdroid.database;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.phoneid.keepassj2me.PwGroup;
+import org.phoneid.keepassj2me.PwManager;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.keepass.R;
+import com.keepassdroid.Database;
+import com.keepassdroid.UIToastTask;
+import com.keepassdroid.keepasslib.PwManagerOutputException;
+
+public class AddGroup implements Runnable {
+ private Database mDb;
+ private String mName;
+ private PwGroup mParent;
+ private Handler mHandler;
+ private Context mCtx;
+ private boolean mNoSave;
+
+ public AddGroup(Database db, Context ctx, String name, PwGroup parent, Handler handler, boolean noSave) {
+ mDb = db;
+ mCtx = ctx;
+ mName = name;
+ mParent = parent;
+ mHandler = handler;
+ mNoSave = noSave;
+ }
+
+ @Override
+ public void run() {
+ PwManager pm = mDb.mPM;
+
+ // Generate new group
+ PwGroup group = pm.newGroup(mName, mParent);
+
+ // Commit to disk
+ if ( ! mNoSave ) {
+ try {
+ mDb.SaveData();
+ } catch (PwManagerOutputException e) {
+ pm.removeGroup(group);
+ mHandler.post(new UIToastTask(mCtx, R.string.error_could_not_create_group));
+ return;
+ } catch (IOException e) {
+ pm.removeGroup(group);
+ mHandler.post(new UIToastTask(mCtx, R.string.error_could_not_create_group));
+ return;
+ }
+ }
+
+ // Mark parent group dirty
+ mDb.gDirty.put(mParent, new WeakReference(mParent));
+
+ // Add group to global list
+ mDb.gGroups.put(group.groupId, new WeakReference(group));
+
+ }
+
+}
diff --git a/src/com/keepassdroid/database/DeleteEntry.java b/src/com/keepassdroid/database/DeleteEntry.java
new file mode 100644
index 000000000..32a803dd6
--- /dev/null
+++ b/src/com/keepassdroid/database/DeleteEntry.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
+package com.keepassdroid.database;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.Vector;
+
+import org.phoneid.keepassj2me.PwEntry;
+import org.phoneid.keepassj2me.PwGroup;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.keepassdroid.Database;
+import com.keepassdroid.UIToastTask;
+import com.keepassdroid.keepasslib.PwManagerOutputException;
+import com.keepassdroid.search.SearchDbHelper;
+
+/** Task to delete entries
+ * @author bpellin
+ *
+ */
+public class DeleteEntry implements Runnable {
+
+ private Database mDb;
+ private Vector mEntries;
+ private Context mCtx;
+ private Handler mHandler;
+ private boolean mDontSave;
+
+ public DeleteEntry(Database db, PwEntry entry, Context ctx, Handler handler) {
+ Vector entries = new Vector();
+ entries.add(entry);
+
+ setMembers(db, entries, ctx, handler, false);
+ }
+
+ public DeleteEntry(Database db, Vector entries, Context ctx, Handler handler, boolean dontSave) {
+ setMembers(db, entries, ctx, handler, dontSave);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void setMembers(Database db, Vector entries, Context ctx, Handler handler, boolean dontSave) {
+ mDb = db;
+ mEntries = (Vector) entries.clone();
+ mCtx = ctx;
+ mHandler = handler;
+ mDontSave = dontSave;
+ }
+
+ @Override
+ public void run() {
+ SearchDbHelper dbHelper = new SearchDbHelper(mCtx);
+ dbHelper.open();
+
+ for ( int i = 0; i < mEntries.size(); i++ ) {
+ PwEntry entry = mEntries.get(i);
+ if ( entry != null ) {
+ removeEntry(entry, dbHelper);
+ }
+ }
+
+ dbHelper.close();
+ }
+
+ private void removeEntry(PwEntry entry, SearchDbHelper dbHelper) {
+ // Remove Entry from parent
+ PwGroup parent = entry.parent;
+ parent.childEntries.remove(entry);
+
+ // Remove Entry from PwManager
+ mDb.mPM.entries.remove(entry);
+
+ // Save
+ if ( ! mDontSave ) {
+ try {
+ mDb.SaveData();
+ } catch (IOException e) {
+ saveError(entry, e.getMessage());
+ return;
+ } catch (PwManagerOutputException e) {
+ saveError(entry, e.getMessage());
+ return;
+ }
+ }
+
+ // Remove from entry global
+ mDb.gEntries.remove(entry);
+
+ // Remove from search db
+ dbHelper.deleteEntry(entry);
+
+ // Mark parent dirty
+ if ( parent != null ) {
+ mDb.gDirty.put(parent, new WeakReference(parent));
+ }
+
+ }
+
+ private void saveError(PwEntry entry, String msg) {
+ undoRemoveEntry(entry);
+ mHandler.post(new UIToastTask(mCtx, msg));
+ }
+
+ private void undoRemoveEntry(PwEntry entry) {
+ mDb.mPM.entries.add(entry);
+
+ PwGroup parent = entry.parent;
+ if ( parent != null ) {
+ parent.childEntries.add(entry);
+ }
+ }
+
+}
diff --git a/src/com/keepassdroid/database/DeleteGroup.java b/src/com/keepassdroid/database/DeleteGroup.java
index 0d19442de..eb7c0bbd6 100644
--- a/src/com/keepassdroid/database/DeleteGroup.java
+++ b/src/com/keepassdroid/database/DeleteGroup.java
@@ -1,33 +1,92 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
package com.keepassdroid.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.util.Vector;
+import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import android.content.Context;
import android.os.Handler;
import com.keepassdroid.Database;
-import com.keepassdroid.UIToastTask;
+import com.keepassdroid.GroupBaseActivity;
import com.keepassdroid.keepasslib.PwManagerOutputException;
public class DeleteGroup implements Runnable {
private Database mDb;
private PwGroup mGroup;
- private Handler uiHandler;
+ private Handler mHandler;
+ private GroupBaseActivity mAct;
private Context mCtx;
+ private boolean mDontSave;
- public DeleteGroup(Database db, PwGroup group, Context ctx, Handler handler) {
+ public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Handler handler) {
+ setMembers(db, group, act, act, handler, false);
+ }
+
+ public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Handler handler, boolean dontSave) {
+ setMembers(db, group, act, act, handler, dontSave);
+ }
+
+ public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Context ctx, Handler handler, boolean dontSave) {
+ setMembers(db, group, act, ctx, handler, dontSave);
+ }
+
+
+ public DeleteGroup(Database db, PwGroup group, Context ctx, Handler handler, boolean dontSave) {
+ setMembers(db, group, null, ctx, handler, dontSave);
+ }
+
+ private void setMembers(Database db, PwGroup group, GroupBaseActivity act, Context ctx, Handler handler, boolean dontSave) {
mDb = db;
mGroup = group;
- uiHandler = handler;
+ mHandler = handler;
+ mAct = act;
mCtx = ctx;
+ mDontSave = dontSave;
}
+
+
@Override
public void run() {
+ // Remove child entries
+ Vector childEnt = mGroup.childEntries;
+ if ( childEnt.size() > 0 ) {
+ DeleteEntry task = new DeleteEntry(mDb, childEnt, mCtx, mHandler, true);
+ task.run();
+ }
+
+ // Remove child groups
+ Vector childGrp = mGroup.childGroups;
+ for ( int i = 0; i < childGrp.size(); i++ ) {
+ DeleteGroup task = new DeleteGroup(mDb, childGrp.get(i), mAct, mCtx, mHandler, true);
+ task.run();
+ }
+
+
// Remove from parent
PwGroup parent = mGroup.parent;
if ( parent != null ) {
@@ -38,36 +97,40 @@ public class DeleteGroup implements Runnable {
mDb.mPM.groups.remove(mGroup);
// Save
- try {
- mDb.SaveData();
- } catch (IOException e) {
- saveError(e.getMessage());
- return;
- } catch (PwManagerOutputException e) {
- saveError(e.getMessage());
- return;
+ if ( ! mDontSave ) {
+ try {
+ mDb.SaveData();
+ } catch (IOException e) {
+ saveError(e.getMessage());
+ return;
+ } catch (PwManagerOutputException e) {
+ saveError(e.getMessage());
+ return;
+ }
}
// Remove from group global
mDb.gGroups.remove(mGroup.groupId);
+ // Remove group from the dirty global (if it is present), not a big deal if this fails
+ try {
+ mDb.gDirty.remove(mGroup);
+ } catch ( Exception e) {
+ // Suppress
+ }
+
// Mark parent dirty
- mDb.gDirty.put(parent, new WeakReference(mGroup));
+ if ( parent != null ) {
+ mDb.gDirty.put(parent, new WeakReference(parent));
+ }
}
private void saveError(String msg) {
- undoRemoveGroup();
- uiHandler.post(new UIToastTask(mCtx, msg));
+ // Let's not bother recovering from a failure to save a deleted group. It is too much work.
+ if ( mAct != null ) {
+ mHandler.post(mAct.new FatalError(msg));
+ }
}
- private void undoRemoveGroup() {
- mDb.mPM.groups.add(mGroup);
-
- PwGroup parent = mGroup.parent;
- if ( parent != null ) {
- parent.childGroups.add(mGroup);
- }
-
- }
}
diff --git a/src/com/keepassdroid/database/UpdateEntry.java b/src/com/keepassdroid/database/UpdateEntry.java
new file mode 100644
index 000000000..12e7e3746
--- /dev/null
+++ b/src/com/keepassdroid/database/UpdateEntry.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
+package com.keepassdroid.database;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.phoneid.keepassj2me.PwEntry;
+import org.phoneid.keepassj2me.PwGroup;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.keepassdroid.Database;
+import com.keepassdroid.UIToastTask;
+import com.keepassdroid.keepasslib.PwManagerOutputException;
+
+public class UpdateEntry implements Runnable {
+ private Database mDb;
+ private Context mCtx;
+ private PwEntry mOldE;
+ private PwEntry mNewE;
+ private Handler mHandler;
+
+ public UpdateEntry(Database db, Context ctx, PwEntry oldE, PwEntry newE, Handler handler) {
+ mDb = db;
+ mCtx = ctx;
+ mOldE = oldE;
+ mNewE = newE;
+ mHandler = handler;
+ }
+
+ @Override
+ public void run() {
+ // Keep backup of original values in case save fails
+ PwEntry backup = new PwEntry(mOldE);
+
+ // Update entry with new values
+ mOldE.assign(mNewE);
+
+ try {
+ mDb.SaveData();
+ } catch (PwManagerOutputException e) {
+ undoUpdateEntry(mOldE, backup);
+ mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
+ } catch (IOException e) {
+ undoUpdateEntry(mOldE, backup);
+ mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
+ }
+
+ // Mark group dirty if title changes
+ if ( ! mOldE.title.equals(mNewE.title) ) {
+ PwGroup parent = mOldE.parent;
+ if ( parent != null ) {
+ // Mark parent group dirty
+ mDb.gDirty.put(parent, new WeakReference(parent));
+ }
+ }
+
+ // Update search index
+ mDb.searchHelper.updateEntry(mOldE);
+ }
+
+ private void undoUpdateEntry(PwEntry old, PwEntry backup) {
+ // If we fail to save, back out changes to global structure
+ old.assign(backup);
+ }
+
+}
diff --git a/src/com/keepassdroid/keepasslib/PwManagerOutput.java b/src/com/keepassdroid/keepasslib/PwManagerOutput.java
index 3304ce076..bcb5d158c 100644
--- a/src/com/keepassdroid/keepasslib/PwManagerOutput.java
+++ b/src/com/keepassdroid/keepasslib/PwManagerOutput.java
@@ -76,6 +76,9 @@ public class PwManagerOutput {
public void output() throws PwManagerOutputException {
+ // Before we output the header, we should sort our list of groups and remove any orphaned nodes that are no longer part of the group hierarchy
+ sortGroupsForOutput();
+
PwDbHeader header = outputHeader(mOS);
byte[] finalKey = getFinalKey(header);
@@ -174,9 +177,14 @@ public class PwManagerOutput {
//long size = 0;
// Groups
- Vector roots = mPM.getGrpRoots();
- for (int i = 0; i < roots.size(); i++ ) {
- outputGroups(os, roots.get(i));
+ for ( int i = 0; i < mPM.groups.size(); i++ ) {
+ PwGroup pg = mPM.groups.get(i);
+ PwGroupOutput pgo = new PwGroupOutput(pg, os);
+ try {
+ pgo.output();
+ } catch (IOException e) {
+ throw new PwManagerOutputException("Failed to output a group: " + e.getMessage());
+ }
}
// Entries
@@ -191,18 +199,25 @@ public class PwManagerOutput {
}
}
- public void outputGroups(OutputStream os, PwGroup group) throws PwManagerOutputException {
- // Output the current group
- PwGroupOutput pgo = new PwGroupOutput(group, os);
- try {
- pgo.output();
- } catch (IOException e) {
- throw new PwManagerOutputException("Failed to output a group: " + e.getMessage());
+ private void sortGroupsForOutput() {
+ Vector groupList = new Vector();
+
+ // Rebuild list according to coalation sorting order removing any orphaned groups
+ Vector roots = mPM.getGrpRoots();
+ for ( int i = 0; i < roots.size(); i++ ) {
+ sortGroup(roots.get(i), groupList);
}
- // Output the child groups
+ mPM.groups = groupList;
+ }
+
+ private void sortGroup(PwGroup group, Vector groupList) {
+ // Add current group
+ groupList.add(group);
+
+ // Recurse over children
for ( int i = 0; i < group.childGroups.size(); i++ ) {
- outputGroups(os, group.childGroups.get(i));
+ sortGroup(group.childGroups.get(i), groupList);
}
}
}
diff --git a/src/com/keepassdroid/search/SearchDbHelper.java b/src/com/keepassdroid/search/SearchDbHelper.java
index fdf117c16..29dcd6fc9 100644
--- a/src/com/keepassdroid/search/SearchDbHelper.java
+++ b/src/com/keepassdroid/search/SearchDbHelper.java
@@ -118,9 +118,14 @@ public class SearchDbHelper {
ContentValues cv = buildNewEntryContent(entry);
String uuidStr = cv.getAsString(KEY_UUID);
- mDb.update(SEARCH_TABLE, cv, KEY_UUID + "= ?", new String[] {uuidStr});
-
+ mDb.update(SEARCH_TABLE, cv, KEY_UUID + " = ?", new String[] {uuidStr});
+ }
+
+ public void deleteEntry(PwEntry entry) {
+ UUID uuid = Types.bytestoUUID(entry.uuid);
+ String uuidStr = uuid.toString();
+ mDb.delete(SEARCH_TABLE, KEY_UUID + " = ?", new String[] {uuidStr});
}
public PwGroup search(Database db, String qStr) {
diff --git a/tests/src/com/keepassdroid/tests/AccentTest.java b/tests/src/com/keepassdroid/tests/AccentTest.java
index b3a9c47ee..e2e63a532 100644
--- a/tests/src/com/keepassdroid/tests/AccentTest.java
+++ b/tests/src/com/keepassdroid/tests/AccentTest.java
@@ -21,7 +21,7 @@ package com.keepassdroid.tests;
import android.test.AndroidTestCase;
-import com.keepassdroid.tests.output.TestData;
+import com.keepassdroid.tests.database.TestData;
public class AccentTest extends AndroidTestCase {
diff --git a/tests/src/com/keepassdroid/tests/PwEntryTest.java b/tests/src/com/keepassdroid/tests/PwEntryTest.java
index 308eb39a9..269664482 100644
--- a/tests/src/com/keepassdroid/tests/PwEntryTest.java
+++ b/tests/src/com/keepassdroid/tests/PwEntryTest.java
@@ -28,7 +28,7 @@ import org.phoneid.keepassj2me.PwEntry;
import android.test.AndroidTestCase;
-import com.keepassdroid.tests.output.TestData;
+import com.keepassdroid.tests.database.TestData;
public class PwEntryTest extends AndroidTestCase {
PwEntry mPE;
diff --git a/tests/src/com/keepassdroid/tests/PwGroupTest.java b/tests/src/com/keepassdroid/tests/PwGroupTest.java
index 541f61f47..51b7151b7 100644
--- a/tests/src/com/keepassdroid/tests/PwGroupTest.java
+++ b/tests/src/com/keepassdroid/tests/PwGroupTest.java
@@ -23,7 +23,7 @@ import org.phoneid.keepassj2me.PwGroup;
import android.test.AndroidTestCase;
-import com.keepassdroid.tests.output.TestData;
+import com.keepassdroid.tests.database.TestData;
public class PwGroupTest extends AndroidTestCase {
diff --git a/tests/src/com/keepassdroid/tests/database/DeleteEntry.java b/tests/src/com/keepassdroid/tests/database/DeleteEntry.java
new file mode 100644
index 000000000..597dfed28
--- /dev/null
+++ b/tests/src/com/keepassdroid/tests/database/DeleteEntry.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2009 Brian Pellin.
+ *
+ * This file is part of KeePassDroid.
+ *
+ * KeePassDroid is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * KeePassDroid 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KeePassDroid. If not, see .
+ *
+ */
+package com.keepassdroid.tests.database;
+
+import java.util.Vector;
+
+import org.phoneid.keepassj2me.PwEntry;
+import org.phoneid.keepassj2me.PwGroup;
+import org.phoneid.keepassj2me.PwManager;
+
+import android.content.Context;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+
+import com.keepassdroid.Database;
+import com.keepassdroid.database.DeleteGroup;
+import com.keepassdroid.search.SearchDbHelper;
+
+public class DeleteEntry extends AndroidTestCase {
+ private static final String GROUP1_NAME = "Group1";
+ private static final String ENTRY1_NAME = "Test1";
+ private static final String ENTRY2_NAME = "Test2";
+ private static final String KEYFILE = "";
+ private static final String PASSWORD = "12345";
+ private static final String ASSET = "delete.kdb";
+ private static final String FILENAME = "/sdcard/delete.kdb";
+
+ public void testDelete() {
+
+ Database db;
+
+ Context ctx = getContext();
+
+ try {
+ db = TestData.GetDb(ctx, ASSET, PASSWORD, KEYFILE, FILENAME);
+ } catch (Exception e) {
+ assertTrue("Failed to open database: " + e.getMessage(), false);
+ return;
+ }
+
+
+ PwGroup group1 = getGroup(db.mPM, GROUP1_NAME);
+ assertNotNull("Could not find group1", group1);
+
+ // Delete the group
+ DeleteGroup task = new DeleteGroup(db, group1, ctx, new Handler(), true);
+ task.run();
+
+ // Verify the entries were deleted
+ PwEntry entry1 = getEntry(db.mPM, ENTRY1_NAME);
+ assertNull("Entry 1 was not removed", entry1);
+
+ PwEntry entry2 = getEntry(db.mPM, ENTRY2_NAME);
+ assertNull("Entry 2 was not removed", entry2);
+
+ // Verify the entries were removed from the search index
+ SearchDbHelper dbHelp = new SearchDbHelper(ctx);
+ dbHelp.open();
+ PwGroup results1 = dbHelp.search(db, ENTRY1_NAME);
+ PwGroup results2 = dbHelp.search(db, ENTRY2_NAME);
+ dbHelp.close();
+
+ assertEquals("Entry1 was not removed from the search results", 0, results1.childEntries.size());
+ assertEquals("Entry2 was not removed from the search results", 0, results2.childEntries.size());
+
+ // Verify the group was deleted
+ group1 = getGroup(db.mPM, GROUP1_NAME);
+ assertNull("Group 1 was not removed.", group1);
+
+
+
+ }
+
+ private PwEntry getEntry(PwManager pm, String name) {
+ Vector entries = pm.entries;
+ for ( int i = 0; i < entries.size(); i++ ) {
+ PwEntry entry = entries.get(i);
+ if ( entry.title.equals(name) ) {
+ return entry;
+ }
+ }
+
+ return null;
+
+ }
+
+ private PwGroup getGroup(PwManager pm, String name) {
+ Vector groups = pm.groups;
+ for ( int i = 0; i < groups.size(); i++ ) {
+ PwGroup group = groups.get(i);
+ if ( group.name.equals(name) ) {
+ return group;
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/tests/src/com/keepassdroid/tests/output/TestData.java b/tests/src/com/keepassdroid/tests/database/TestData.java
similarity index 98%
rename from tests/src/com/keepassdroid/tests/output/TestData.java
rename to tests/src/com/keepassdroid/tests/database/TestData.java
index eb260da70..938d869d7 100644
--- a/tests/src/com/keepassdroid/tests/output/TestData.java
+++ b/tests/src/com/keepassdroid/tests/database/TestData.java
@@ -17,7 +17,7 @@
* along with KeePassDroid. If not, see .
*
*/
-package com.keepassdroid.tests.output;
+package com.keepassdroid.tests.database;
import java.io.IOException;
import java.io.InputStream;
diff --git a/tests/src/com/keepassdroid/tests/output/PwManagerOutputTest.java b/tests/src/com/keepassdroid/tests/output/PwManagerOutputTest.java
index a637daada..f8cc61ba5 100644
--- a/tests/src/com/keepassdroid/tests/output/PwManagerOutputTest.java
+++ b/tests/src/com/keepassdroid/tests/output/PwManagerOutputTest.java
@@ -39,6 +39,7 @@ import com.keepassdroid.keepasslib.NullOutputStream;
import com.keepassdroid.keepasslib.PwDbHeaderOutput;
import com.keepassdroid.keepasslib.PwManagerOutput;
import com.keepassdroid.keepasslib.PwManagerOutputException;
+import com.keepassdroid.tests.database.TestData;
public class PwManagerOutputTest extends AndroidTestCase {
PwManager mPM;
diff --git a/tests/src/com/keepassdroid/tests/search/SearchTest.java b/tests/src/com/keepassdroid/tests/search/SearchTest.java
index eeb986140..8e791cc36 100644
--- a/tests/src/com/keepassdroid/tests/search/SearchTest.java
+++ b/tests/src/com/keepassdroid/tests/search/SearchTest.java
@@ -24,7 +24,7 @@ import org.phoneid.keepassj2me.PwGroup;
import android.test.AndroidTestCase;
import com.keepassdroid.Database;
-import com.keepassdroid.tests.output.TestData;
+import com.keepassdroid.tests.database.TestData;
public class SearchTest extends AndroidTestCase {
@@ -38,6 +38,7 @@ public class SearchTest extends AndroidTestCase {
}
public void testSearch() {
+
PwGroup results = mDb.Search("Amazon");
assertTrue("Search result not found.", results.childEntries.size() > 0);