mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Multiple action node for Move Copy and Delete
This commit is contained in:
@@ -33,10 +33,7 @@ import com.kunzisoft.keepass.activities.dialogs.GeneratePasswordDialogFragment
|
|||||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||||
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
||||||
import com.kunzisoft.keepass.database.action.node.ActionNodeValues
|
import com.kunzisoft.keepass.database.action.node.*
|
||||||
import com.kunzisoft.keepass.database.action.node.AddEntryRunnable
|
|
||||||
import com.kunzisoft.keepass.database.action.node.AfterActionNodeFinishRunnable
|
|
||||||
import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable
|
|
||||||
import com.kunzisoft.keepass.database.element.*
|
import com.kunzisoft.keepass.database.element.*
|
||||||
import com.kunzisoft.keepass.education.EntryEditActivityEducation
|
import com.kunzisoft.keepass.education.EntryEditActivityEducation
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
|
|||||||
import com.kunzisoft.keepass.database.SortNodeEnum
|
import com.kunzisoft.keepass.database.SortNodeEnum
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
||||||
import com.kunzisoft.keepass.database.action.node.*
|
import com.kunzisoft.keepass.database.action.node.*
|
||||||
import com.kunzisoft.keepass.database.action.node.ActionNodeDatabaseRunnable.Companion.NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY
|
|
||||||
import com.kunzisoft.keepass.database.element.*
|
import com.kunzisoft.keepass.database.element.*
|
||||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||||
@@ -502,93 +501,47 @@ class GroupActivity : LockingActivity(),
|
|||||||
|
|
||||||
override fun onPasteMenuClick(pasteMode: ListNodesFragment.PasteMode?,
|
override fun onPasteMenuClick(pasteMode: ListNodesFragment.PasteMode?,
|
||||||
nodes: List<NodeVersioned>): Boolean {
|
nodes: List<NodeVersioned>): Boolean {
|
||||||
// TODO multiple paste
|
when (pasteMode) {
|
||||||
nodes.forEach { currentNode ->
|
ListNodesFragment.PasteMode.PASTE_FROM_COPY -> {
|
||||||
when (pasteMode) {
|
// Copy
|
||||||
ListNodesFragment.PasteMode.PASTE_FROM_COPY -> {
|
mCurrentGroup?.let { newParent ->
|
||||||
// COPY
|
ProgressDialogSaveDatabaseThread(this) {
|
||||||
when (currentNode.type) {
|
CopyNodesRunnable(this,
|
||||||
Type.GROUP -> Log.e(TAG, "Copy not allowed for group")
|
Database.getInstance(),
|
||||||
Type.ENTRY -> {
|
nodes,
|
||||||
mCurrentGroup?.let { newParent ->
|
newParent,
|
||||||
ProgressDialogSaveDatabaseThread(this) {
|
AfterAddNodeRunnable(),
|
||||||
CopyEntryRunnable(this,
|
!mReadOnly)
|
||||||
Database.getInstance(),
|
}.start()
|
||||||
currentNode as EntryVersioned,
|
|
||||||
newParent,
|
|
||||||
AfterAddNodeRunnable(),
|
|
||||||
!mReadOnly)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ListNodesFragment.PasteMode.PASTE_FROM_MOVE -> {
|
ListNodesFragment.PasteMode.PASTE_FROM_MOVE -> {
|
||||||
// Move
|
// Move
|
||||||
when (currentNode.type) {
|
mCurrentGroup?.let { newParent ->
|
||||||
Type.GROUP -> {
|
ProgressDialogSaveDatabaseThread(this) {
|
||||||
mCurrentGroup?.let { newParent ->
|
MoveNodesRunnable(
|
||||||
ProgressDialogSaveDatabaseThread(this) {
|
this,
|
||||||
MoveGroupRunnable(
|
Database.getInstance(),
|
||||||
this,
|
nodes,
|
||||||
Database.getInstance(),
|
newParent,
|
||||||
currentNode as GroupVersioned,
|
AfterAddNodeRunnable(),
|
||||||
newParent,
|
!mReadOnly)
|
||||||
AfterAddNodeRunnable(),
|
}.start()
|
||||||
!mReadOnly)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type.ENTRY -> {
|
|
||||||
mCurrentGroup?.let { newParent ->
|
|
||||||
ProgressDialogSaveDatabaseThread(this) {
|
|
||||||
MoveEntryRunnable(
|
|
||||||
this,
|
|
||||||
Database.getInstance(),
|
|
||||||
currentNode as EntryVersioned,
|
|
||||||
newParent,
|
|
||||||
AfterAddNodeRunnable(),
|
|
||||||
!mReadOnly)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finishNodeAction()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean {
|
override fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean {
|
||||||
// TODO multiple delete
|
ProgressDialogSaveDatabaseThread(this) {
|
||||||
nodes.forEach { currentNode ->
|
DeleteNodesRunnable(
|
||||||
when (currentNode.type) {
|
this,
|
||||||
Type.GROUP -> {
|
Database.getInstance(),
|
||||||
//TODO Verify trash recycle bin
|
nodes,
|
||||||
ProgressDialogSaveDatabaseThread(this) {
|
AfterDeleteNodeRunnable(),
|
||||||
DeleteGroupRunnable(
|
!mReadOnly)
|
||||||
this,
|
}.start()
|
||||||
Database.getInstance(),
|
|
||||||
currentNode as GroupVersioned,
|
|
||||||
AfterDeleteNodeRunnable(),
|
|
||||||
!mReadOnly)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
Type.ENTRY -> {
|
|
||||||
ProgressDialogSaveDatabaseThread(this) {
|
|
||||||
DeleteEntryRunnable(
|
|
||||||
this,
|
|
||||||
Database.getInstance(),
|
|
||||||
currentNode as EntryVersioned,
|
|
||||||
AfterDeleteNodeRunnable(),
|
|
||||||
!mReadOnly)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finishNodeAction()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,8 +729,7 @@ class GroupActivity : LockingActivity(),
|
|||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,9 +738,9 @@ class GroupActivity : LockingActivity(),
|
|||||||
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (actionNodeValues.result.isSuccess) {
|
if (actionNodeValues.result.isSuccess) {
|
||||||
if (actionNodeValues.newNode != null)
|
mListNodesFragment?.addNodes(actionNodeValues.newNodes)
|
||||||
mListNodesFragment?.addNode(actionNodeValues.newNode)
|
|
||||||
}
|
}
|
||||||
|
finishNodeAction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -797,9 +749,9 @@ class GroupActivity : LockingActivity(),
|
|||||||
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (actionNodeValues.result.isSuccess) {
|
if (actionNodeValues.result.isSuccess) {
|
||||||
if (actionNodeValues.oldNode!= null && actionNodeValues.newNode != null)
|
mListNodesFragment?.updateNodes(actionNodeValues.oldNodes, actionNodeValues.newNodes)
|
||||||
mListNodesFragment?.updateNode(actionNodeValues.oldNode, actionNodeValues.newNode)
|
|
||||||
}
|
}
|
||||||
|
finishNodeAction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -809,16 +761,12 @@ class GroupActivity : LockingActivity(),
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (actionNodeValues.result.isSuccess) {
|
if (actionNodeValues.result.isSuccess) {
|
||||||
|
|
||||||
// If the action register the position, use it to remove the entry view
|
// Rebuold all the list the avoid bug when delete node from db sort
|
||||||
val positionNode = actionNodeValues.result.data?.getInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY)
|
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB) {
|
||||||
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB
|
mListNodesFragment?.rebuildList()
|
||||||
&& positionNode != null) {
|
|
||||||
mListNodesFragment?.removeNodeAt(positionNode)
|
|
||||||
} else {
|
} else {
|
||||||
// Use the old Node that was the entry unchanged with the old parent
|
// Use the old Nodes / entries unchanged with the old parent
|
||||||
actionNodeValues.oldNode?.let { oldNode ->
|
mListNodesFragment?.removeNodes(actionNodeValues.oldNodes)
|
||||||
mListNodesFragment?.removeNode(oldNode)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add trash in views list if it doesn't exists
|
// Add trash in views list if it doesn't exists
|
||||||
@@ -835,6 +783,7 @@ class GroupActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finishNodeAction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,18 +366,34 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
mAdapter?.addNode(newNode)
|
mAdapter?.addNode(newNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addNodes(newNodes: List<NodeVersioned>) {
|
||||||
|
mAdapter?.addNodes(newNodes)
|
||||||
|
}
|
||||||
|
|
||||||
fun updateNode(oldNode: NodeVersioned, newNode: NodeVersioned? = null) {
|
fun updateNode(oldNode: NodeVersioned, newNode: NodeVersioned? = null) {
|
||||||
mAdapter?.updateNode(oldNode, newNode ?: oldNode)
|
mAdapter?.updateNode(oldNode, newNode ?: oldNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateNodes(oldNodes: List<NodeVersioned>, newNodes: List<NodeVersioned>) {
|
||||||
|
mAdapter?.updateNodes(oldNodes, newNodes)
|
||||||
|
}
|
||||||
|
|
||||||
fun removeNode(pwNode: NodeVersioned) {
|
fun removeNode(pwNode: NodeVersioned) {
|
||||||
mAdapter?.removeNode(pwNode)
|
mAdapter?.removeNode(pwNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeNodes(nodes: List<NodeVersioned>) {
|
||||||
|
mAdapter?.removeNodes(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
fun removeNodeAt(position: Int) {
|
fun removeNodeAt(position: Int) {
|
||||||
mAdapter?.removeNodeAt(position)
|
mAdapter?.removeNodeAt(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeNodesAt(positions: IntArray) {
|
||||||
|
mAdapter?.removeNodesAt(positions)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback listener to redefine to do an action when a node is click
|
* Callback listener to redefine to do an action when a node is click
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -156,6 +156,14 @@ class NodeAdapter
|
|||||||
nodeSortedList.add(node)
|
nodeSortedList.add(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add nodes to the list
|
||||||
|
* @param nodes Nodes to add
|
||||||
|
*/
|
||||||
|
fun addNodes(nodes: List<NodeVersioned>) {
|
||||||
|
nodeSortedList.addAll(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a node in the list
|
* Remove a node in the list
|
||||||
* @param node Node to delete
|
* @param node Node to delete
|
||||||
@@ -164,6 +172,16 @@ class NodeAdapter
|
|||||||
nodeSortedList.remove(node)
|
nodeSortedList.remove(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove nodes in the list
|
||||||
|
* @param nodes Nodes to delete
|
||||||
|
*/
|
||||||
|
fun removeNodes(nodes: List<NodeVersioned>) {
|
||||||
|
nodes.forEach { node ->
|
||||||
|
nodeSortedList.remove(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a node at [position] in the list
|
* Remove a node at [position] in the list
|
||||||
*/
|
*/
|
||||||
@@ -173,6 +191,18 @@ class NodeAdapter
|
|||||||
notifyItemRangeChanged(position, nodeSortedList.size() - position)
|
notifyItemRangeChanged(position, nodeSortedList.size() - position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove nodes in the list by [positions]
|
||||||
|
* Note : algorithm remove the higher position at each iteration
|
||||||
|
*/
|
||||||
|
fun removeNodesAt(positions: IntArray) {
|
||||||
|
val positionsSortDescending = positions.toMutableList()
|
||||||
|
positionsSortDescending.sortDescending()
|
||||||
|
positionsSortDescending.forEach {
|
||||||
|
removeNodeAt(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a node in the list
|
* Update a node in the list
|
||||||
* @param oldNode Node before the update
|
* @param oldNode Node before the update
|
||||||
@@ -185,6 +215,20 @@ class NodeAdapter
|
|||||||
nodeSortedList.endBatchedUpdates()
|
nodeSortedList.endBatchedUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update nodes in the list
|
||||||
|
* @param oldNodes Nodes before the update
|
||||||
|
* @param newNodes Node after the update
|
||||||
|
*/
|
||||||
|
fun updateNodes(oldNodes: List<NodeVersioned>, newNodes: List<NodeVersioned>) {
|
||||||
|
nodeSortedList.beginBatchedUpdates()
|
||||||
|
oldNodes.forEach { oldNode ->
|
||||||
|
nodeSortedList.remove(oldNode)
|
||||||
|
}
|
||||||
|
nodeSortedList.addAll(newNodes)
|
||||||
|
nodeSortedList.endBatchedUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
fun notifyNodeChanged(node: NodeVersioned) {
|
fun notifyNodeChanged(node: NodeVersioned) {
|
||||||
notifyItemChanged(nodeSortedList.indexOf(node))
|
notifyItemChanged(nodeSortedList.indexOf(node))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,4 @@ abstract class ActionNodeDatabaseRunnable(
|
|||||||
|
|
||||||
super.onFinishRun(result)
|
super.onFinishRun(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY = "NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import androidx.fragment.app.FragmentActivity
|
|||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||||
|
|
||||||
class AddEntryRunnable constructor(
|
class AddEntryRunnable constructor(
|
||||||
context: FragmentActivity,
|
context: FragmentActivity,
|
||||||
@@ -45,6 +46,10 @@ class AddEntryRunnable constructor(
|
|||||||
database.removeEntryFrom(mNewEntry, it)
|
database.removeEntryFrom(mNewEntry, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ActionNodeValues(result, null, mNewEntry)
|
|
||||||
|
val oldNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
val newNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
newNodesReturn.add(mNewEntry)
|
||||||
|
return ActionNodeValues(result, oldNodesReturn, newNodesReturn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.action.node
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||||
|
|
||||||
class AddGroupRunnable constructor(
|
class AddGroupRunnable constructor(
|
||||||
context: FragmentActivity,
|
context: FragmentActivity,
|
||||||
@@ -42,6 +43,10 @@ class AddGroupRunnable constructor(
|
|||||||
if (!result.isSuccess) {
|
if (!result.isSuccess) {
|
||||||
database.removeGroupFrom(mNewGroup, mParent)
|
database.removeGroupFrom(mNewGroup, mParent)
|
||||||
}
|
}
|
||||||
return ActionNodeValues(result, null, mNewGroup)
|
|
||||||
|
val oldNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
val newNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
newNodesReturn.add(mNewGroup)
|
||||||
|
return ActionNodeValues(result, oldNodesReturn, newNodesReturn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ import com.kunzisoft.keepass.tasks.ActionRunnable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback method who return the node(s) modified after an action
|
* Callback method who return the node(s) modified after an action
|
||||||
* - Add : @param oldNode NULL, @param newNode CreatedNode
|
* - Add : @param oldNodes empty, @param newNodes CreatedNodes
|
||||||
* - Copy : @param oldNode NodeToCopy, @param newNode NodeCopied
|
* - Copy : @param oldNodes NodesToCopy, @param newNodes NodesCopied
|
||||||
* - Delete : @param oldNode NodeToDelete, @param NULL
|
* - Delete : @param oldNodes NodesToDelete, @param newNodes empty
|
||||||
* - Move : @param oldNode NULL, @param NodeToMove
|
* - Move : @param oldNodes empty, @param newNodes NodesToMove
|
||||||
* - Update : @param oldNode NodeToUpdate, @param NodeUpdated
|
* - Update : @param oldNodes NodesToUpdate, @param newNodes NodesUpdated
|
||||||
*/
|
*/
|
||||||
data class ActionNodeValues(val result: ActionRunnable.Result, val oldNode: NodeVersioned?, val newNode: NodeVersioned?)
|
class ActionNodeValues(val result: ActionRunnable.Result, val oldNodes: List<NodeVersioned>, val newNodes: List<NodeVersioned>)
|
||||||
|
|
||||||
abstract class AfterActionNodeFinishRunnable {
|
abstract class AfterActionNodeFinishRunnable {
|
||||||
abstract fun onActionNodeFinish(actionNodeValues: ActionNodeValues)
|
abstract fun onActionNodeFinish(actionNodeValues: ActionNodeValues)
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import android.util.Log
|
|
||||||
import com.kunzisoft.keepass.R
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
|
||||||
|
|
||||||
class CopyEntryRunnable constructor(
|
|
||||||
context: FragmentActivity,
|
|
||||||
database: Database,
|
|
||||||
private val mEntryToCopy: EntryVersioned,
|
|
||||||
private val mNewParent: GroupVersioned,
|
|
||||||
afterAddNodeRunnable: AfterActionNodeFinishRunnable?,
|
|
||||||
save: Boolean)
|
|
||||||
: ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) {
|
|
||||||
|
|
||||||
private var mEntryCopied: EntryVersioned? = null
|
|
||||||
|
|
||||||
override fun nodeAction() {
|
|
||||||
// Condition
|
|
||||||
var conditionAccepted = true
|
|
||||||
if(mNewParent == database.rootGroup && !database.rootCanContainsEntry())
|
|
||||||
conditionAccepted = false
|
|
||||||
if (conditionAccepted) {
|
|
||||||
// Update entry with new values
|
|
||||||
mNewParent.touch(modified = false, touchParents = true)
|
|
||||||
mEntryCopied = database.copyEntryTo(mEntryToCopy, mNewParent)
|
|
||||||
} else {
|
|
||||||
// Only finish thread
|
|
||||||
throw Exception(context.getString(R.string.error_copy_entry_here))
|
|
||||||
}
|
|
||||||
|
|
||||||
mEntryCopied?.apply {
|
|
||||||
touch(modified = true, touchParents = true)
|
|
||||||
} ?: Log.e(TAG, "Unable to create a copy of the entry")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nodeFinish(result: Result): ActionNodeValues {
|
|
||||||
if (!result.isSuccess) {
|
|
||||||
// If we fail to save, try to delete the copy
|
|
||||||
try {
|
|
||||||
mEntryCopied?.let {
|
|
||||||
database.deleteEntry(it)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.i(TAG, "Unable to delete the copied entry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ActionNodeValues(result, mEntryToCopy, mEntryCopied)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = CopyEntryRunnable::class.java.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.*
|
||||||
|
|
||||||
|
class CopyNodesRunnable constructor(
|
||||||
|
context: FragmentActivity,
|
||||||
|
database: Database,
|
||||||
|
private val mNodesToCopy: List<NodeVersioned>,
|
||||||
|
private val mNewParent: GroupVersioned,
|
||||||
|
afterAddNodeRunnable: AfterActionNodeFinishRunnable?,
|
||||||
|
save: Boolean)
|
||||||
|
: ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) {
|
||||||
|
|
||||||
|
private var mEntriesCopied = ArrayList<EntryVersioned>()
|
||||||
|
|
||||||
|
override fun nodeAction() {
|
||||||
|
|
||||||
|
mNodesToCopy.forEach { currentNode ->
|
||||||
|
|
||||||
|
when (currentNode.type) {
|
||||||
|
Type.GROUP -> Log.e(TAG, "Copy not allowed for group")
|
||||||
|
Type.ENTRY -> {
|
||||||
|
// Root can contains entry
|
||||||
|
if (mNewParent != database.rootGroup || database.rootCanContainsEntry()) {
|
||||||
|
// Update entry with new values
|
||||||
|
mNewParent.touch(modified = false, touchParents = true)
|
||||||
|
database.copyEntryTo(currentNode as EntryVersioned, mNewParent)?.let { entryCopied ->
|
||||||
|
entryCopied.touch(modified = true, touchParents = true)
|
||||||
|
mEntriesCopied.add(entryCopied)
|
||||||
|
} ?: Log.e(TAG, "Unable to create a copy of the entry")
|
||||||
|
} else {
|
||||||
|
// Only finish thread
|
||||||
|
throw Exception(context.getString(R.string.error_copy_entry_here))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nodeFinish(result: Result): ActionNodeValues {
|
||||||
|
if (!result.isSuccess) {
|
||||||
|
// If we fail to save, try to delete the copy
|
||||||
|
mEntriesCopied.forEach {
|
||||||
|
try {
|
||||||
|
database.deleteEntry(it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.i(TAG, "Unable to delete the copied entry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionNodeValues(result, mNodesToCopy, mEntriesCopied)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = CopyNodesRunnable::class.java.name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
|
||||||
|
|
||||||
class DeleteEntryRunnable constructor(
|
|
||||||
context: FragmentActivity,
|
|
||||||
database: Database,
|
|
||||||
private val mEntryToDelete: EntryVersioned,
|
|
||||||
finishRunnable: AfterActionNodeFinishRunnable?,
|
|
||||||
save: Boolean)
|
|
||||||
: ActionNodeDatabaseRunnable(context, database, finishRunnable, save) {
|
|
||||||
|
|
||||||
private var mParent: GroupVersioned? = null
|
|
||||||
private var mCanRecycle: Boolean = false
|
|
||||||
|
|
||||||
private var mEntryToDeleteBackup: EntryVersioned? = null
|
|
||||||
private var mNodePosition: Int? = null
|
|
||||||
|
|
||||||
override fun nodeAction() {
|
|
||||||
mParent = mEntryToDelete.parent
|
|
||||||
mParent?.touch(modified = false, touchParents = true)
|
|
||||||
|
|
||||||
// Get the node position
|
|
||||||
mNodePosition = mEntryToDelete.nodePositionInParent
|
|
||||||
|
|
||||||
// Create a copy to keep the old ref and remove it visually
|
|
||||||
mEntryToDeleteBackup = EntryVersioned(mEntryToDelete)
|
|
||||||
|
|
||||||
// Remove Entry from parent
|
|
||||||
mCanRecycle = database.canRecycle(mEntryToDelete)
|
|
||||||
if (mCanRecycle) {
|
|
||||||
database.recycle(mEntryToDelete, context.resources)
|
|
||||||
} else {
|
|
||||||
database.deleteEntry(mEntryToDelete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nodeFinish(result: Result): ActionNodeValues {
|
|
||||||
if (!result.isSuccess) {
|
|
||||||
mParent?.let {
|
|
||||||
if (mCanRecycle) {
|
|
||||||
database.undoRecycle(mEntryToDelete, it)
|
|
||||||
} else {
|
|
||||||
database.undoDeleteEntry(mEntryToDelete, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add position in bundle to delete the node in view
|
|
||||||
mNodePosition?.let { position ->
|
|
||||||
result.data = Bundle().apply {
|
|
||||||
putInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY, position )
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
result.data?.remove(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a copy of unchanged entry as old param
|
|
||||||
// and entry deleted or moved in recycle bin as new param
|
|
||||||
return ActionNodeValues(result, mEntryToDeleteBackup, mEntryToDelete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
|
||||||
|
|
||||||
class DeleteGroupRunnable(context: FragmentActivity,
|
|
||||||
database: Database,
|
|
||||||
private val mGroupToDelete: GroupVersioned,
|
|
||||||
finish: AfterActionNodeFinishRunnable,
|
|
||||||
save: Boolean) : ActionNodeDatabaseRunnable(context, database, finish, save) {
|
|
||||||
private var mParent: GroupVersioned? = null
|
|
||||||
private var mRecycle: Boolean = false
|
|
||||||
|
|
||||||
private var mGroupToDeleteBackup: GroupVersioned? = null
|
|
||||||
private var mNodePosition: Int? = null
|
|
||||||
|
|
||||||
override fun nodeAction() {
|
|
||||||
mParent = mGroupToDelete.parent
|
|
||||||
mParent?.touch(modified = false, touchParents = true)
|
|
||||||
|
|
||||||
// Get the node position
|
|
||||||
mNodePosition = mGroupToDelete.nodePositionInParent
|
|
||||||
|
|
||||||
// Create a copy to keep the old ref and remove it visually
|
|
||||||
mGroupToDeleteBackup = GroupVersioned(mGroupToDelete)
|
|
||||||
|
|
||||||
// Remove Group from parent
|
|
||||||
mRecycle = database.canRecycle(mGroupToDelete)
|
|
||||||
if (mRecycle) {
|
|
||||||
database.recycle(mGroupToDelete, context.resources)
|
|
||||||
} else {
|
|
||||||
database.deleteGroup(mGroupToDelete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nodeFinish(result: Result): ActionNodeValues {
|
|
||||||
if (!result.isSuccess) {
|
|
||||||
if (mRecycle) {
|
|
||||||
mParent?.let {
|
|
||||||
database.undoRecycle(mGroupToDelete, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// else {
|
|
||||||
// Let's not bother recovering from a failure to save a deleted tree. It is too much work.
|
|
||||||
// TODO database.undoDeleteGroupFrom(mGroup, mParent);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add position in bundle to delete the node in view
|
|
||||||
mNodePosition?.let { position ->
|
|
||||||
result.data = Bundle().apply {
|
|
||||||
putInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY, position )
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
result.data?.remove(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a copy of unchanged group as old param
|
|
||||||
// and group deleted or moved in recycle bin as new param
|
|
||||||
return ActionNodeValues(result, mGroupToDeleteBackup, mGroupToDelete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import com.kunzisoft.keepass.database.element.*
|
||||||
|
|
||||||
|
class DeleteNodesRunnable(context: FragmentActivity,
|
||||||
|
database: Database,
|
||||||
|
private val mNodesToDelete: List<NodeVersioned>,
|
||||||
|
finish: AfterActionNodeFinishRunnable,
|
||||||
|
save: Boolean) : ActionNodeDatabaseRunnable(context, database, finish, save) {
|
||||||
|
private var mParent: GroupVersioned? = null
|
||||||
|
private var mCanRecycle: Boolean = false
|
||||||
|
|
||||||
|
private var mNodesToDeleteBackup = ArrayList<NodeVersioned>()
|
||||||
|
|
||||||
|
override fun nodeAction() {
|
||||||
|
|
||||||
|
mNodesToDelete.forEach { currentNode ->
|
||||||
|
mParent = currentNode.parent
|
||||||
|
mParent?.touch(modified = false, touchParents = true)
|
||||||
|
|
||||||
|
when (currentNode.type) {
|
||||||
|
Type.GROUP -> {
|
||||||
|
// Create a copy to keep the old ref and remove it visually
|
||||||
|
mNodesToDeleteBackup.add(GroupVersioned(currentNode as GroupVersioned))
|
||||||
|
// Remove Node from parent
|
||||||
|
mCanRecycle = database.canRecycle(currentNode)
|
||||||
|
if (mCanRecycle) {
|
||||||
|
database.recycle(currentNode, context.resources)
|
||||||
|
} else {
|
||||||
|
database.deleteGroup(currentNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type.ENTRY -> {
|
||||||
|
// Create a copy to keep the old ref and remove it visually
|
||||||
|
mNodesToDeleteBackup.add(EntryVersioned(currentNode as EntryVersioned))
|
||||||
|
// Remove Node from parent
|
||||||
|
mCanRecycle = database.canRecycle(currentNode)
|
||||||
|
if (mCanRecycle) {
|
||||||
|
database.recycle(currentNode, context.resources)
|
||||||
|
} else {
|
||||||
|
database.deleteEntry(currentNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nodeFinish(result: Result): ActionNodeValues {
|
||||||
|
if (!result.isSuccess) {
|
||||||
|
if (mCanRecycle) {
|
||||||
|
mParent?.let {
|
||||||
|
mNodesToDeleteBackup.forEach { backupNode ->
|
||||||
|
when (backupNode.type) {
|
||||||
|
Type.GROUP -> {
|
||||||
|
database.undoRecycle(backupNode as GroupVersioned, it)
|
||||||
|
}
|
||||||
|
Type.ENTRY -> {
|
||||||
|
database.undoRecycle(backupNode as EntryVersioned, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// Let's not bother recovering from a failure to save a deleted tree. It is too much work.
|
||||||
|
// TODO database.undoDeleteGroupFrom(mGroup, mParent);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a copy of unchanged nodes as old param
|
||||||
|
// and nodes deleted or moved in recycle bin as new param
|
||||||
|
return ActionNodeValues(result, mNodesToDeleteBackup, mNodesToDelete)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import android.util.Log
|
|
||||||
import com.kunzisoft.keepass.R
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
|
||||||
|
|
||||||
class MoveEntryRunnable constructor(
|
|
||||||
context: FragmentActivity,
|
|
||||||
database: Database,
|
|
||||||
private val mEntryToMove: EntryVersioned?,
|
|
||||||
private val mNewParent: GroupVersioned,
|
|
||||||
afterAddNodeRunnable: AfterActionNodeFinishRunnable?,
|
|
||||||
save: Boolean)
|
|
||||||
: ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) {
|
|
||||||
|
|
||||||
private var mOldParent: GroupVersioned? = null
|
|
||||||
|
|
||||||
override fun nodeAction() {
|
|
||||||
// Move entry in new parent
|
|
||||||
mEntryToMove?.let {
|
|
||||||
mOldParent = it.parent
|
|
||||||
|
|
||||||
// Condition
|
|
||||||
var conditionAccepted = true
|
|
||||||
if(mNewParent == database.rootGroup && !database.rootCanContainsEntry())
|
|
||||||
conditionAccepted = false
|
|
||||||
// Move only if the parent change
|
|
||||||
if (mOldParent != mNewParent && conditionAccepted) {
|
|
||||||
database.moveEntryTo(it, mNewParent)
|
|
||||||
} else {
|
|
||||||
// Only finish thread
|
|
||||||
throw Exception(context.getString(R.string.error_move_entry_here))
|
|
||||||
}
|
|
||||||
it.touch(modified = true, touchParents = true)
|
|
||||||
} ?: Log.e(TAG, "Unable to create a copy of the entry")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nodeFinish(result: Result): ActionNodeValues {
|
|
||||||
if (!result.isSuccess) {
|
|
||||||
// If we fail to save, try to remove in the first place
|
|
||||||
try {
|
|
||||||
if (mEntryToMove != null && mOldParent != null)
|
|
||||||
database.moveEntryTo(mEntryToMove, mOldParent!!)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.i(TAG, "Unable to replace the entry")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return ActionNodeValues(result, null, mEntryToMove)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = MoveEntryRunnable::class.java.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import android.util.Log
|
|
||||||
import com.kunzisoft.keepass.R
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
|
||||||
|
|
||||||
class MoveGroupRunnable constructor(
|
|
||||||
context: FragmentActivity,
|
|
||||||
database: Database,
|
|
||||||
private val mGroupToMove: GroupVersioned?,
|
|
||||||
private val mNewParent: GroupVersioned,
|
|
||||||
afterAddNodeRunnable: AfterActionNodeFinishRunnable?,
|
|
||||||
save: Boolean)
|
|
||||||
: ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) {
|
|
||||||
|
|
||||||
private var mOldParent: GroupVersioned? = null
|
|
||||||
|
|
||||||
override fun nodeAction() {
|
|
||||||
mGroupToMove?.let {
|
|
||||||
mOldParent = it.parent
|
|
||||||
// Move group in new parent if not in the current group
|
|
||||||
if (mGroupToMove != mNewParent && !mNewParent.isContainedIn(mGroupToMove)) {
|
|
||||||
database.moveGroupTo(mGroupToMove, mNewParent)
|
|
||||||
mGroupToMove.touch(modified = true, touchParents = true)
|
|
||||||
finishRun(true)
|
|
||||||
} else {
|
|
||||||
// Only finish thread
|
|
||||||
throw Exception(context.getString(R.string.error_move_folder_in_itself))
|
|
||||||
}
|
|
||||||
} ?: Log.e(TAG, "Unable to create a copy of the group")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nodeFinish(result: Result): ActionNodeValues {
|
|
||||||
if (!result.isSuccess) {
|
|
||||||
// If we fail to save, try to move in the first place
|
|
||||||
try {
|
|
||||||
if (mGroupToMove != null && mOldParent != null)
|
|
||||||
database.moveGroupTo(mGroupToMove, mOldParent!!)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.i(TAG, "Unable to replace the group")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return ActionNodeValues(result, null, mGroupToMove)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = MoveGroupRunnable::class.java.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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 3 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.kunzisoft.keepass.database.action.node
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import android.util.Log
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.*
|
||||||
|
|
||||||
|
class MoveNodesRunnable constructor(
|
||||||
|
context: FragmentActivity,
|
||||||
|
database: Database,
|
||||||
|
private val mNodesToMove: List<NodeVersioned>,
|
||||||
|
private val mNewParent: GroupVersioned,
|
||||||
|
afterAddNodeRunnable: AfterActionNodeFinishRunnable?,
|
||||||
|
save: Boolean)
|
||||||
|
: ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) {
|
||||||
|
|
||||||
|
private var mOldParent: GroupVersioned? = null
|
||||||
|
|
||||||
|
override fun nodeAction() {
|
||||||
|
|
||||||
|
mNodesToMove.forEach { nodeToMove ->
|
||||||
|
// Move node in new parent
|
||||||
|
mOldParent = nodeToMove.parent
|
||||||
|
|
||||||
|
when (nodeToMove.type) {
|
||||||
|
Type.GROUP -> {
|
||||||
|
val groupToMove = nodeToMove as GroupVersioned
|
||||||
|
// Move group in new parent if not in the current group
|
||||||
|
if (groupToMove != mNewParent
|
||||||
|
&& !mNewParent.isContainedIn(groupToMove)) {
|
||||||
|
database.moveGroupTo(groupToMove, mNewParent)
|
||||||
|
finishRun(true)
|
||||||
|
} else {
|
||||||
|
// Only finish thread
|
||||||
|
throw Exception(context.getString(R.string.error_move_folder_in_itself))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type.ENTRY -> {
|
||||||
|
val entryToMove = nodeToMove as EntryVersioned
|
||||||
|
// Move only if the parent change
|
||||||
|
if (mOldParent != mNewParent
|
||||||
|
// and root can contains entry
|
||||||
|
&& (mNewParent != database.rootGroup || database.rootCanContainsEntry())) {
|
||||||
|
database.moveEntryTo(entryToMove, mNewParent)
|
||||||
|
finishRun(true)
|
||||||
|
} else {
|
||||||
|
// Only finish thread
|
||||||
|
throw Exception(context.getString(R.string.error_move_entry_here))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeToMove.touch(modified = true, touchParents = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nodeFinish(result: Result): ActionNodeValues {
|
||||||
|
if (!result.isSuccess) {
|
||||||
|
try {
|
||||||
|
mNodesToMove.forEach { nodeToMove ->
|
||||||
|
// If we fail to save, try to move in the first place
|
||||||
|
if (mOldParent != null) {
|
||||||
|
when (nodeToMove.type) {
|
||||||
|
Type.GROUP -> database.moveGroupTo(nodeToMove as GroupVersioned, mOldParent!!)
|
||||||
|
Type.ENTRY -> database.moveEntryTo(nodeToMove as EntryVersioned, mOldParent!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.i(TAG, "Unable to replace the node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionNodeValues(result, ArrayList(), mNodesToMove)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = MoveNodesRunnable::class.java.name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.action.node
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||||
|
|
||||||
class UpdateEntryRunnable constructor(
|
class UpdateEntryRunnable constructor(
|
||||||
context: FragmentActivity,
|
context: FragmentActivity,
|
||||||
@@ -55,6 +56,11 @@ class UpdateEntryRunnable constructor(
|
|||||||
mOldEntry.updateWith(it)
|
mOldEntry.updateWith(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ActionNodeValues(result, mOldEntry, mNewEntry)
|
|
||||||
|
val oldNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
oldNodesReturn.add(mOldEntry)
|
||||||
|
val newNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
newNodesReturn.add(mNewEntry)
|
||||||
|
return ActionNodeValues(result, oldNodesReturn, newNodesReturn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.action.node
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||||
|
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||||
|
|
||||||
class UpdateGroupRunnable constructor(
|
class UpdateGroupRunnable constructor(
|
||||||
context: FragmentActivity,
|
context: FragmentActivity,
|
||||||
@@ -46,6 +47,11 @@ class UpdateGroupRunnable constructor(
|
|||||||
// If we fail to save, back out changes to global structure
|
// If we fail to save, back out changes to global structure
|
||||||
mOldGroup.updateWith(mBackupGroup)
|
mOldGroup.updateWith(mBackupGroup)
|
||||||
}
|
}
|
||||||
return ActionNodeValues(result, mOldGroup, mNewGroup)
|
|
||||||
|
val oldNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
oldNodesReturn.add(mOldGroup)
|
||||||
|
val newNodesReturn = ArrayList<NodeVersioned>()
|
||||||
|
newNodesReturn.add(mNewGroup)
|
||||||
|
return ActionNodeValues(result, oldNodesReturn, newNodesReturn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ interface NodeVersioned: PwNodeInterface<GroupVersioned> {
|
|||||||
val nodePositionInParent: Int
|
val nodePositionInParent: Int
|
||||||
get() {
|
get() {
|
||||||
parent?.getChildren(true)?.let { children ->
|
parent?.getChildren(true)?.let { children ->
|
||||||
for ((i, child) in children.withIndex()) {
|
children.forEachIndexed { index, nodeVersioned ->
|
||||||
if (child == this)
|
if (nodeVersioned == this)
|
||||||
return i
|
return index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
Reference in New Issue
Block a user