mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Solve bugs when update node in list, start encapsulate code
This commit is contained in:
@@ -74,8 +74,8 @@ public class DeleteEntry extends AndroidTestCase {
|
||||
PwGroup results1 = dbHelp.search(db, ENTRY1_NAME);
|
||||
PwGroup results2 = dbHelp.search(db, ENTRY2_NAME);
|
||||
|
||||
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());
|
||||
assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries());
|
||||
assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries());
|
||||
|
||||
// Verify the group was deleted
|
||||
group1 = getGroup(pm, GROUP1_NAME);
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SearchTest extends AndroidTestCase {
|
||||
|
||||
public void testSearch() {
|
||||
PwGroup results = mDb.Search("Amazon");
|
||||
assertTrue("Search result not found.", results.childEntries.size() > 0);
|
||||
assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
|
||||
|
||||
}
|
||||
|
||||
@@ -51,14 +51,14 @@ public class SearchTest extends AndroidTestCase {
|
||||
updateOmitSetting(false);
|
||||
PwGroup results = mDb.Search("BackupOnly");
|
||||
|
||||
assertTrue("Search result not found.", results.childEntries.size() > 0);
|
||||
assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
|
||||
}
|
||||
|
||||
public void testBackupExcluded() {
|
||||
updateOmitSetting(true);
|
||||
PwGroup results = mDb.Search("BackupOnly");
|
||||
|
||||
assertFalse("Search result found, but should not have been.", results.childEntries.size() > 0);
|
||||
assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0);
|
||||
}
|
||||
|
||||
private void updateOmitSetting(boolean setting) {
|
||||
|
||||
@@ -34,13 +34,8 @@ import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.keepassdroid.database.Database;
|
||||
import com.keepassdroid.fragments.GeneratePasswordDialogFragment;
|
||||
import com.keepassdroid.fragments.IconPickerDialogFragment;
|
||||
import com.keepassdroid.tasks.ProgressTask;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.Database;
|
||||
import com.keepassdroid.database.PwDatabase;
|
||||
import com.keepassdroid.database.PwEntry;
|
||||
import com.keepassdroid.database.PwEntryV3;
|
||||
@@ -54,10 +49,15 @@ import com.keepassdroid.database.edit.AddEntry;
|
||||
import com.keepassdroid.database.edit.OnFinish;
|
||||
import com.keepassdroid.database.edit.RunnableOnFinish;
|
||||
import com.keepassdroid.database.edit.UpdateEntry;
|
||||
import com.keepassdroid.fragments.GeneratePasswordDialogFragment;
|
||||
import com.keepassdroid.fragments.IconPickerDialogFragment;
|
||||
import com.keepassdroid.icons.Icons;
|
||||
import com.keepassdroid.tasks.ProgressTask;
|
||||
import com.keepassdroid.utils.MenuUtil;
|
||||
import com.keepassdroid.utils.Types;
|
||||
import com.keepassdroid.utils.Util;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -189,7 +189,7 @@ public abstract class EntryEditActivity extends LockCloseHideActivity
|
||||
PwEntry newEntry = populateNewEntry();
|
||||
|
||||
RunnableOnFinish task;
|
||||
OnFinish onFinish = act.new AfterSave(new Handler());
|
||||
OnFinish onFinish = new AfterSave();
|
||||
|
||||
Intent intentEntry = new Intent();
|
||||
if ( mIsNew ) {
|
||||
@@ -198,7 +198,7 @@ public abstract class EntryEditActivity extends LockCloseHideActivity
|
||||
setResult(ADD_ENTRY_RESULT_CODE, intentEntry);
|
||||
} else {
|
||||
task = new UpdateEntry(act, App.getDB(), mEntry, newEntry, onFinish);
|
||||
intentEntry.putExtra(ADD_OR_UPDATE_ENTRY_KEY, mEntry);
|
||||
intentEntry.putExtra(ADD_OR_UPDATE_ENTRY_KEY, newEntry);
|
||||
setResult(UPDATE_ENTRY_RESULT_CODE, intentEntry);
|
||||
}
|
||||
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
|
||||
@@ -322,8 +322,8 @@ public abstract class EntryEditActivity extends LockCloseHideActivity
|
||||
|
||||
private final class AfterSave extends OnFinish {
|
||||
|
||||
AfterSave(Handler handler) {
|
||||
super(handler);
|
||||
AfterSave() {
|
||||
super(new Handler());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -251,7 +251,7 @@ public abstract class GroupActivity extends GroupBaseActivity
|
||||
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE)
|
||||
mAdapter.addNode(newNode);
|
||||
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE)
|
||||
mAdapter.updateNode(newNode);
|
||||
mAdapter.updateLastNodeClicked();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -261,8 +261,8 @@ public abstract class GroupBaseActivity extends LockCloseListActivity
|
||||
db.dirty.remove(mGroup);
|
||||
|
||||
// Tell the adapter to refresh it's list
|
||||
// TODO mAdapter.sort();
|
||||
mAdapter.notifyDataSetChanged();
|
||||
mAdapter.notifyChangeSort();
|
||||
mAdapter.rebuildList(mGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package com.keepassdroid.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -13,6 +33,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.PwGroup;
|
||||
import com.keepassdroid.database.PwNode;
|
||||
import com.keepassdroid.settings.PrefsUtil;
|
||||
import com.kunzisoft.keepass.R;
|
||||
@@ -27,25 +48,30 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
private Context context;
|
||||
private LayoutInflater inflater;
|
||||
private float textSize;
|
||||
private boolean sortByName;
|
||||
|
||||
private OnNodeClickCallback onNodeClickCallback;
|
||||
private int nodePositionToUpdate;
|
||||
private NodeMenuListener nodeMenuListener;
|
||||
|
||||
public NodeAdapter(final Context context, PwNode mainNode) {
|
||||
public NodeAdapter(final Context context, PwGroup mainNode) {
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.context = context;
|
||||
this.textSize = PrefsUtil.getListTextSize(context);
|
||||
this.sortByName = PrefsUtil.isListSortByName(context);
|
||||
this.nodePositionToUpdate = -1;
|
||||
|
||||
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
|
||||
@Override public int compare(PwNode item1, PwNode item2) {
|
||||
if(PrefsUtil.isListSortByName(context))
|
||||
return item1.compareTo(item2);
|
||||
// Choose sort depend of preferences
|
||||
if(sortByName)
|
||||
return new PwNode.NodeNameComparator().compare(item1, item2);
|
||||
else
|
||||
return item1.compareTo(item2); // TODO Different sort
|
||||
return new PwNode.NodeCreationComparator().compare(item1, item2);
|
||||
}
|
||||
|
||||
@Override public boolean areContentsTheSame(PwNode oldItem, PwNode newItem) {
|
||||
return oldItem.equals(newItem);
|
||||
return oldItem.isContentVisuallyTheSame(newItem);
|
||||
}
|
||||
|
||||
@Override public boolean areItemsTheSame(PwNode item1, PwNode item2) {
|
||||
@@ -55,22 +81,51 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
this.nodeSortedList.addAll(mainNode.getDirectChildren());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the list by clear and build again for the group
|
||||
*/
|
||||
public void rebuildList(PwGroup group) {
|
||||
this.nodeSortedList.clear();
|
||||
this.nodeSortedList.addAll(group.getDirectChildren());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the list
|
||||
* @param node Node to add
|
||||
*/
|
||||
public void addNode(PwNode node) {
|
||||
nodeSortedList.add(node);
|
||||
}
|
||||
|
||||
public void updateNode(PwNode node) {
|
||||
/**
|
||||
* Update the last Node clicked in the list
|
||||
*/
|
||||
public void updateLastNodeClicked() {
|
||||
// Don't really update here, sorted list knows each original ref, so we just notify a change
|
||||
try {
|
||||
nodeSortedList.updateItemAt(nodeSortedList.indexOf(node), node);
|
||||
notifyItemChanged(nodePositionToUpdate);
|
||||
nodeSortedList.recalculatePositionOfItemAt(nodePositionToUpdate);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
Log.e(NodeAdapter.class.getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove node in the list
|
||||
* @param node Node to delete
|
||||
*/
|
||||
public void removeNode(PwNode node) {
|
||||
nodeSortedList.remove(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify a change sort of the list
|
||||
*/
|
||||
// TODO as interface
|
||||
public void notifyChangeSort() {
|
||||
this.sortByName = PrefsUtil.isListSortByName(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return nodeSortedList.get(position).getType().ordinal();
|
||||
@@ -112,19 +167,39 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
return nodeSortedList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a listener when a node is clicked
|
||||
*/
|
||||
public void setOnNodeClickListener(OnNodeClickCallback onNodeClickCallback) {
|
||||
this.onNodeClickCallback = onNodeClickCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a listener when an element of menu is clicked
|
||||
*/
|
||||
public void setNodeMenuListener(NodeMenuListener nodeMenuListener) {
|
||||
this.nodeMenuListener = nodeMenuListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback listener to redefine to do an action when a node is click
|
||||
*/
|
||||
public interface OnNodeClickCallback {
|
||||
void onNodeClick(PwNode node);
|
||||
}
|
||||
|
||||
public class OnNodeClickListener implements View.OnClickListener {
|
||||
/**
|
||||
* Menu listener to redefine to do an action in menu
|
||||
*/
|
||||
public interface NodeMenuListener {
|
||||
boolean onOpenMenuClick(PwNode node);
|
||||
boolean onDeleteMenuClick(PwNode node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for node listener
|
||||
*/
|
||||
private class OnNodeClickListener implements View.OnClickListener {
|
||||
private PwNode node;
|
||||
|
||||
OnNodeClickListener(PwNode node) {
|
||||
@@ -133,16 +208,15 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
nodePositionToUpdate = nodeSortedList.indexOf(node);
|
||||
if (onNodeClickCallback != null)
|
||||
onNodeClickCallback.onNodeClick(node);
|
||||
}
|
||||
}
|
||||
|
||||
public interface NodeMenuListener {
|
||||
boolean onOpenMenuClick(PwNode node);
|
||||
boolean onDeleteMenuClick(PwNode node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for menu listener
|
||||
*/
|
||||
private class ContextMenuBuilder implements View.OnCreateContextMenuListener {
|
||||
|
||||
private PwNode node;
|
||||
|
||||
@@ -256,7 +256,7 @@ public abstract class PwDatabase {
|
||||
parent = rootGroup;
|
||||
}
|
||||
|
||||
parent.childGroups.add(newGroup);
|
||||
parent.addChildGroup(newGroup);
|
||||
newGroup.setParent(parent);
|
||||
groups.put(newGroup.getId(), newGroup);
|
||||
|
||||
@@ -265,7 +265,7 @@ public abstract class PwDatabase {
|
||||
|
||||
public void removeGroupFrom(PwGroup remove, PwGroup parent) {
|
||||
// Remove tree from parent tree
|
||||
parent.childGroups.remove(remove);
|
||||
parent.removeChildGroup(remove);
|
||||
|
||||
groups.remove(remove.getId());
|
||||
}
|
||||
@@ -273,7 +273,7 @@ public abstract class PwDatabase {
|
||||
public void addEntryTo(PwEntry newEntry, PwGroup parent) {
|
||||
// Add entry to parent
|
||||
if (parent != null) {
|
||||
parent.childEntries.add(newEntry);
|
||||
parent.addChildEntry(newEntry);
|
||||
}
|
||||
newEntry.setParent(parent);
|
||||
|
||||
@@ -283,7 +283,7 @@ public abstract class PwDatabase {
|
||||
public void removeEntryFrom(PwEntry remove, PwGroup parent) {
|
||||
// Remove entry for parent
|
||||
if (parent != null) {
|
||||
parent.childEntries.remove(remove);
|
||||
parent.removeChildEntry(remove);
|
||||
}
|
||||
entries.remove(remove.getUUID());
|
||||
}
|
||||
|
||||
@@ -179,12 +179,12 @@ public class PwDatabaseV3 extends PwDatabase {
|
||||
currentGroup.childEntries = getEntries(currentGroup);
|
||||
|
||||
// set parent in child entries
|
||||
for (int i = 0; i < currentGroup.childEntries.size(); i++) {
|
||||
for (int i = 0; i < currentGroup.numbersOfChildEntries(); i++) {
|
||||
PwEntryV3 entry = (PwEntryV3) currentGroup.childEntries.get(i);
|
||||
entry.parent = currentGroup;
|
||||
}
|
||||
// recursively construct child groups
|
||||
for (int i = 0; i < currentGroup.childGroups.size(); i++) {
|
||||
for (int i = 0; i < currentGroup.numbersOfChildGroups(); i++) {
|
||||
PwGroupV3 grp = (PwGroupV3) currentGroup.childGroups.get(i);
|
||||
grp.parent = currentGroup;
|
||||
constructTree((PwGroupV3) currentGroup.childGroups.get(i));
|
||||
|
||||
@@ -29,20 +29,8 @@ public abstract class PwEntry extends PwNode implements Cloneable {
|
||||
|
||||
protected static final String PMS_TAN_ENTRY = "<TAN>";
|
||||
|
||||
public static class EntryNameComparator implements Comparator<PwEntry> {
|
||||
|
||||
public int compare(PwEntry object1, PwEntry object2) {
|
||||
return object1.getTitle().compareToIgnoreCase(object2.getTitle());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PwIconStandard icon = PwIconStandard.FIRST;
|
||||
|
||||
public PwEntry() {
|
||||
|
||||
}
|
||||
|
||||
public static PwEntry getInstance(PwGroup parent) {
|
||||
return PwEntry.getInstance(parent, true, true);
|
||||
}
|
||||
@@ -183,4 +171,53 @@ public abstract class PwEntry extends PwNode implements Cloneable {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PwEntry pwEntry = (PwEntry) o;
|
||||
return isSameType(pwEntry)
|
||||
&& (getUUID() != null ? getUUID().equals(pwEntry.getUUID()) : pwEntry.getUUID() == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getUUID() != null ? getUUID().hashCode() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator of Entry by Name
|
||||
*/
|
||||
public static class EntryNameComparator implements Comparator<PwEntry> {
|
||||
public int compare(PwEntry object1, PwEntry object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
int entryTitleComp = object1.getTitle().compareToIgnoreCase(object2.getTitle());
|
||||
// If same title, can be different
|
||||
if (entryTitleComp == 0) {
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
}
|
||||
return entryTitleComp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator of Entry by Creation
|
||||
*/
|
||||
public static class EntryCreationComparator implements Comparator<PwEntry> {
|
||||
public int compare(PwEntry object1, PwEntry object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
int entryCreationComp = object1.getCreationTime().compareTo(object2.getCreationTime());
|
||||
// If same creation, can be different
|
||||
if (entryCreationComp == 0) {
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
}
|
||||
return entryCreationComp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,31 +19,51 @@
|
||||
*/
|
||||
package com.keepassdroid.database;
|
||||
|
||||
import com.keepassdroid.utils.StrUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.keepassdroid.utils.StrUtil;
|
||||
|
||||
public abstract class PwGroup extends PwNode {
|
||||
|
||||
// TODO Change dependency and make private
|
||||
public List<PwGroup> childGroups = new ArrayList<>();
|
||||
public List<PwEntry> childEntries = new ArrayList<>();
|
||||
public String name = "";
|
||||
public PwIconStandard icon;
|
||||
|
||||
@Override
|
||||
public List<PwNode> getDirectChildren() {
|
||||
List<PwNode> children = new ArrayList<>();
|
||||
children.addAll(childGroups);
|
||||
children.addAll(childEntries);
|
||||
return children;
|
||||
private List<PwNode> children = new ArrayList<>();
|
||||
|
||||
public void initNewGroup(String nm, PwGroupId newId) {
|
||||
setId(newId);
|
||||
name = nm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfDirectChildren() {
|
||||
return childGroups.size() + childEntries.size();
|
||||
public void addChildGroup(PwGroup group) {
|
||||
this.childGroups.add(group);
|
||||
}
|
||||
|
||||
public void addChildEntry(PwEntry entry) {
|
||||
this.childEntries.add(entry);
|
||||
}
|
||||
|
||||
public void removeChildGroup(PwGroup group) {
|
||||
this.childGroups.remove(group);
|
||||
}
|
||||
|
||||
public void removeChildEntry(PwEntry entry) {
|
||||
this.childEntries.remove(entry);
|
||||
}
|
||||
|
||||
public int numbersOfChildGroups() {
|
||||
return childGroups.size();
|
||||
}
|
||||
|
||||
public int numbersOfChildEntries() {
|
||||
return childEntries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,9 +71,38 @@ public abstract class PwGroup extends PwNode {
|
||||
return Type.GROUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of direct children (one level below) as PwNode
|
||||
*/
|
||||
public List<PwNode> getDirectChildren() {
|
||||
children.clear();
|
||||
children.addAll(childGroups);
|
||||
children.addAll(childEntries);
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of direct elements in Node (one level below)
|
||||
* @return Size of child elements, default is 0
|
||||
*/
|
||||
public int numberOfDirectChildren() {
|
||||
return childGroups.size() + childEntries.size();
|
||||
}
|
||||
|
||||
public abstract PwGroup getParent();
|
||||
public abstract void setParent(PwGroup parent);
|
||||
|
||||
public boolean isContainedIn(PwGroup container) {
|
||||
PwGroup cur = this;
|
||||
while (cur != null) {
|
||||
if (cur == container) {
|
||||
return true;
|
||||
}
|
||||
cur = cur.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract PwGroupId getId();
|
||||
public abstract void setId(PwGroupId id);
|
||||
|
||||
@@ -70,43 +119,12 @@ public abstract class PwGroup extends PwNode {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static class GroupNameComparator implements Comparator<PwGroup> {
|
||||
|
||||
public int compare(PwGroup object1, PwGroup object2) {
|
||||
return object1.getName().compareToIgnoreCase(object2.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void setLastAccessTime(Date date);
|
||||
|
||||
public abstract void setLastModificationTime(Date date);
|
||||
|
||||
public void sortEntriesByName() {
|
||||
Collections.sort(childEntries, new PwEntry.EntryNameComparator());
|
||||
}
|
||||
|
||||
public void initNewGroup(String nm, PwGroupId newId) {
|
||||
setId(newId);
|
||||
name = nm;
|
||||
}
|
||||
|
||||
public boolean isContainedIn(PwGroup container) {
|
||||
PwGroup cur = this;
|
||||
while (cur != null) {
|
||||
if (cur == container) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cur = cur.getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void touch(boolean modified, boolean touchParents) {
|
||||
Date now = new Date();
|
||||
|
||||
setLastAccessTime(now);
|
||||
|
||||
if (modified) {
|
||||
@@ -119,7 +137,6 @@ public abstract class PwGroup extends PwNode {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void searchEntries(SearchParameters sp, List<PwEntry> listStorage) {
|
||||
if (sp == null) { return; }
|
||||
if (listStorage == null) { return; }
|
||||
@@ -166,7 +183,6 @@ public abstract class PwGroup extends PwNode {
|
||||
complement.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
pg = complement;
|
||||
}
|
||||
else {
|
||||
@@ -200,19 +216,64 @@ public abstract class PwGroup extends PwNode {
|
||||
if (entryHandler != null) {
|
||||
for (PwEntry entry : childEntries) {
|
||||
if (!entryHandler.operate(entry)) return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (PwGroup group : childGroups) {
|
||||
|
||||
if ((groupHandler != null) && !groupHandler.operate(group)) return false;
|
||||
|
||||
group.preOrderTraverseTree(groupHandler, entryHandler);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PwGroup pwGroup = (PwGroup) o;
|
||||
return isSameType(pwGroup)
|
||||
&& (getId() != null ? getId().equals(pwGroup.getId()) : pwGroup.getId() == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
PwGroupId groupId = getId();
|
||||
return groupId != null ? groupId.hashCode() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group comparator by name
|
||||
*/
|
||||
public static class GroupNameComparator implements Comparator<PwGroup> {
|
||||
public int compare(PwGroup object1, PwGroup object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
int groupNameComp = object1.getName().compareToIgnoreCase(object2.getName());
|
||||
// If same name, can be different
|
||||
if (groupNameComp == 0) {
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
}
|
||||
return groupNameComp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Group comparator by name
|
||||
*/
|
||||
public static class GroupCreationComparator implements Comparator<PwGroup> {
|
||||
public int compare(PwGroup object1, PwGroup object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
int groupCreationComp = object1.getCreationTime().compareTo(object2.getCreationTime());
|
||||
// If same creation, can be different
|
||||
if (groupCreationComp == 0) {
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
}
|
||||
return groupCreationComp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class PwGroupIdV3 extends PwGroupId {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
Integer i = Integer.valueOf(id);
|
||||
Integer i = id;
|
||||
return i.hashCode();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Brian Pellin <bpellin@gmail.com>
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
@@ -43,8 +41,6 @@ import java.util.List;
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
*/
|
||||
public class PwGroupV3 extends PwGroup {
|
||||
public PwGroupV3() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
@@ -155,4 +151,11 @@ public class PwGroupV3 extends PwGroup {
|
||||
tLastMod = new PwDate(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreationTime() {
|
||||
if(tCreation != null)
|
||||
return tCreation.getJDate();
|
||||
else
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger {
|
||||
private long usageCount = 0;
|
||||
public Map<String, String> customData = new HashMap<String, String>();
|
||||
|
||||
public PwGroupV4() {
|
||||
|
||||
}
|
||||
public PwGroupV4() {}
|
||||
|
||||
public PwGroupV4(boolean createUUID, boolean setTimes, String name, PwIconStandard icon) {
|
||||
if (createUUID) {
|
||||
@@ -87,7 +85,7 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger {
|
||||
public void AddEntry(PwEntryV4 pe, boolean takeOwnership, boolean updateLocationChanged) {
|
||||
assert(pe != null);
|
||||
|
||||
childEntries.add(pe);
|
||||
addChildEntry(pe);
|
||||
|
||||
if ( takeOwnership ) pe.parent = this;
|
||||
|
||||
@@ -102,7 +100,7 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger {
|
||||
public void buildChildGroupsRecursive(List<PwGroup> list) {
|
||||
list.add(this);
|
||||
|
||||
for ( int i = 0; i < childGroups.size(); i++) {
|
||||
for ( int i = 0; i < numbersOfChildGroups(); i++) {
|
||||
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
|
||||
child.buildChildGroupsRecursive(list);
|
||||
|
||||
@@ -110,11 +108,11 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger {
|
||||
}
|
||||
|
||||
public void buildChildEntriesRecursive(List<PwEntry> list) {
|
||||
for ( int i = 0; i < childEntries.size(); i++ ) {
|
||||
for ( int i = 0; i < numbersOfChildEntries(); i++ ) {
|
||||
list.add(childEntries.get(i));
|
||||
}
|
||||
|
||||
for ( int i = 0; i < childGroups.size(); i++ ) {
|
||||
for ( int i = 0; i < numbersOfChildGroups(); i++ ) {
|
||||
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
|
||||
child.buildChildEntriesRecursive(list);
|
||||
}
|
||||
|
||||
@@ -20,71 +20,133 @@
|
||||
*/
|
||||
package com.keepassdroid.database;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Abstract class who manage Groups and Entries
|
||||
*/
|
||||
public abstract class PwNode implements Comparable<PwNode>, Serializable {
|
||||
public abstract class PwNode implements Serializable {
|
||||
|
||||
/**
|
||||
* Get the type of Node
|
||||
* Type of available Nodes
|
||||
*/
|
||||
public enum Type {
|
||||
GROUP, ENTRY
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Type of Node
|
||||
*/
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* @return title to display as view
|
||||
* @return Title to display as view
|
||||
*/
|
||||
public abstract String getDisplayTitle();
|
||||
|
||||
/**
|
||||
* @return Visual icon
|
||||
*/
|
||||
public abstract PwIcon getIcon();
|
||||
|
||||
/**
|
||||
* @return List of direct children (one level below) as PwNode
|
||||
* @return Creation date and time of the node
|
||||
*/
|
||||
public List<PwNode> getDirectChildren() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
public abstract Date getCreationTime();
|
||||
|
||||
public PwNode getDirectChildAt(int position) {
|
||||
return getDirectChildren().get(position);
|
||||
/**
|
||||
* If the content (type, title, icon) is visually the same
|
||||
* @param o Node to compare
|
||||
* @return True if visually as o
|
||||
*/
|
||||
public boolean isContentVisuallyTheSame(PwNode o) {
|
||||
return getType().equals(o.getType())
|
||||
&& getDisplayTitle().equals(o.getDisplayTitle())
|
||||
&& getIcon().equals(o.getIcon());
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of direct elements in Node (one level below)
|
||||
* @return Size of child elements, default is 0
|
||||
* Define if it's the same type of another node
|
||||
* @param otherNode The other node to test
|
||||
* @return true if both have the same type
|
||||
*/
|
||||
public int numberOfDirectChildren() {
|
||||
return getDirectChildren().size();
|
||||
boolean isSameType(PwNode otherNode) {
|
||||
return getType() != null ? getType().equals(otherNode.getType()) : otherNode.getType() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull PwNode o) {
|
||||
if (this instanceof PwGroup) {
|
||||
if (o instanceof PwGroup) {
|
||||
return new PwGroup.GroupNameComparator().compare((PwGroup) this, (PwGroup) o);
|
||||
} else if (o instanceof PwEntry) {
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (this instanceof PwEntry) {
|
||||
if(o instanceof PwEntry) {
|
||||
return new PwEntry.EntryNameComparator().compare((PwEntry) this, (PwEntry) o);
|
||||
} else if (o instanceof PwGroup) {
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
/**
|
||||
* Comparator of Node by Name, Groups first, Entries second
|
||||
*/
|
||||
public static class NodeNameComparator implements Comparator<PwNode> {
|
||||
public int compare(PwNode object1, PwNode object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
if (object1 instanceof PwGroup) {
|
||||
if (object2 instanceof PwGroup) {
|
||||
return new PwGroup.GroupNameComparator()
|
||||
.compare((PwGroup) object1, (PwGroup) object2);
|
||||
} else if (object2 instanceof PwEntry) {
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (object1 instanceof PwEntry) {
|
||||
if(object2 instanceof PwEntry) {
|
||||
return new PwEntry.EntryNameComparator()
|
||||
.compare((PwEntry) object1, (PwEntry) object2);
|
||||
} else if (object2 instanceof PwGroup) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int nodeNameComp = object1.getDisplayTitle()
|
||||
.compareToIgnoreCase(object2.getDisplayTitle());
|
||||
// If same name, can be different
|
||||
if (nodeNameComp == 0)
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
return nodeNameComp;
|
||||
}
|
||||
return this.getDisplayTitle().compareToIgnoreCase(o.getDisplayTitle());
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
GROUP, ENTRY
|
||||
/**
|
||||
* Comparator of node by creation, Groups first, Entries second
|
||||
*/
|
||||
public static class NodeCreationComparator implements Comparator<PwNode> {
|
||||
@Override
|
||||
public int compare(PwNode object1, PwNode object2) {
|
||||
if (object1.equals(object2))
|
||||
return 0;
|
||||
|
||||
if (object1 instanceof PwGroup) {
|
||||
if (object2 instanceof PwGroup) {
|
||||
return new PwGroup.GroupCreationComparator()
|
||||
.compare((PwGroup) object1, (PwGroup) object2);
|
||||
} else if (object2 instanceof PwEntry) {
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (object1 instanceof PwEntry) {
|
||||
if(object2 instanceof PwEntry) {
|
||||
return new PwEntry.EntryCreationComparator()
|
||||
.compare((PwEntry) object1, (PwEntry) object2);
|
||||
} else if (object2 instanceof PwGroup) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int nodeCreationComp = object1.getCreationTime()
|
||||
.compareTo(object2.getCreationTime());
|
||||
// If same creation, can be different
|
||||
if (nodeCreationComp == 0) {
|
||||
return object1.hashCode() - object2.hashCode();
|
||||
}
|
||||
return nodeCreationComp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class DeleteGroup extends RunnableOnFinish {
|
||||
// Remove from parent
|
||||
PwGroup parent = mGroup.getParent();
|
||||
if ( parent != null ) {
|
||||
parent.childGroups.remove(mGroup);
|
||||
parent.removeChildGroup(mGroup);
|
||||
}
|
||||
|
||||
// Remove from PwDatabaseV3
|
||||
|
||||
@@ -71,16 +71,11 @@ public class UpdateEntry extends RunnableOnFinish {
|
||||
public void run() {
|
||||
if ( mSuccess ) {
|
||||
// Mark group dirty if title or icon changes
|
||||
// TODO CHange if not equal... Why only title and Icon ?
|
||||
if ( ! mBackup.getTitle().equals(mNewE.getTitle()) || ! mBackup.getIcon().equals(mNewE.getIcon()) ) {
|
||||
if ( ! mBackup.isContentVisuallyTheSame(mNewE) ) {
|
||||
PwGroup parent = mBackup.getParent();
|
||||
if ( parent != null ) {
|
||||
// Resort entries
|
||||
parent.sortEntriesByName();
|
||||
|
||||
// Mark parent group dirty
|
||||
mDb.dirty.add(parent);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -260,7 +260,7 @@ public class PwDbV3Output extends PwDbOutput {
|
||||
groupList.add(group);
|
||||
|
||||
// Recurse over children
|
||||
for ( int i = 0; i < group.childGroups.size(); i++ ) {
|
||||
for ( int i = 0; i < group.numbersOfChildGroups(); i++ ) {
|
||||
sortGroup((PwGroupV3) group.childGroups.get(i), groupList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class SearchResultsActivity extends GroupBaseActivity {
|
||||
private void performSearch(String query) {
|
||||
mGroup = mDb.Search(query.trim());
|
||||
|
||||
if ( mGroup == null || mGroup.childEntries.size() < 1 ) {
|
||||
if ( mGroup == null || mGroup.numbersOfChildEntries() < 1 ) {
|
||||
listView.setVisibility(View.GONE);
|
||||
notFoundView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user