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.lock.LockingHideActivity
|
||||
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
||||
import com.kunzisoft.keepass.database.action.node.ActionNodeValues
|
||||
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.action.node.*
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.education.EntryEditActivityEducation
|
||||
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.action.ProgressDialogSaveDatabaseThread
|
||||
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.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
@@ -502,51 +501,28 @@ class GroupActivity : LockingActivity(),
|
||||
|
||||
override fun onPasteMenuClick(pasteMode: ListNodesFragment.PasteMode?,
|
||||
nodes: List<NodeVersioned>): Boolean {
|
||||
// TODO multiple paste
|
||||
nodes.forEach { currentNode ->
|
||||
when (pasteMode) {
|
||||
ListNodesFragment.PasteMode.PASTE_FROM_COPY -> {
|
||||
// COPY
|
||||
when (currentNode.type) {
|
||||
Type.GROUP -> Log.e(TAG, "Copy not allowed for group")
|
||||
Type.ENTRY -> {
|
||||
// Copy
|
||||
mCurrentGroup?.let { newParent ->
|
||||
ProgressDialogSaveDatabaseThread(this) {
|
||||
CopyEntryRunnable(this,
|
||||
CopyNodesRunnable(this,
|
||||
Database.getInstance(),
|
||||
currentNode as EntryVersioned,
|
||||
nodes,
|
||||
newParent,
|
||||
AfterAddNodeRunnable(),
|
||||
!mReadOnly)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListNodesFragment.PasteMode.PASTE_FROM_MOVE -> {
|
||||
// Move
|
||||
when (currentNode.type) {
|
||||
Type.GROUP -> {
|
||||
mCurrentGroup?.let { newParent ->
|
||||
ProgressDialogSaveDatabaseThread(this) {
|
||||
MoveGroupRunnable(
|
||||
MoveNodesRunnable(
|
||||
this,
|
||||
Database.getInstance(),
|
||||
currentNode as GroupVersioned,
|
||||
newParent,
|
||||
AfterAddNodeRunnable(),
|
||||
!mReadOnly)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
Type.ENTRY -> {
|
||||
mCurrentGroup?.let { newParent ->
|
||||
ProgressDialogSaveDatabaseThread(this) {
|
||||
MoveEntryRunnable(
|
||||
this,
|
||||
Database.getInstance(),
|
||||
currentNode as EntryVersioned,
|
||||
nodes,
|
||||
newParent,
|
||||
AfterAddNodeRunnable(),
|
||||
!mReadOnly)
|
||||
@@ -554,41 +530,18 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finishNodeAction()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean {
|
||||
// TODO multiple delete
|
||||
nodes.forEach { currentNode ->
|
||||
when (currentNode.type) {
|
||||
Type.GROUP -> {
|
||||
//TODO Verify trash recycle bin
|
||||
ProgressDialogSaveDatabaseThread(this) {
|
||||
DeleteGroupRunnable(
|
||||
DeleteNodesRunnable(
|
||||
this,
|
||||
Database.getInstance(),
|
||||
currentNode as GroupVersioned,
|
||||
nodes,
|
||||
AfterDeleteNodeRunnable(),
|
||||
!mReadOnly)
|
||||
}.start()
|
||||
}
|
||||
Type.ENTRY -> {
|
||||
ProgressDialogSaveDatabaseThread(this) {
|
||||
DeleteEntryRunnable(
|
||||
this,
|
||||
Database.getInstance(),
|
||||
currentNode as EntryVersioned,
|
||||
AfterDeleteNodeRunnable(),
|
||||
!mReadOnly)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
finishNodeAction()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -776,8 +729,7 @@ class GroupActivity : LockingActivity(),
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -786,9 +738,9 @@ class GroupActivity : LockingActivity(),
|
||||
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
||||
runOnUiThread {
|
||||
if (actionNodeValues.result.isSuccess) {
|
||||
if (actionNodeValues.newNode != null)
|
||||
mListNodesFragment?.addNode(actionNodeValues.newNode)
|
||||
mListNodesFragment?.addNodes(actionNodeValues.newNodes)
|
||||
}
|
||||
finishNodeAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -797,9 +749,9 @@ class GroupActivity : LockingActivity(),
|
||||
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
|
||||
runOnUiThread {
|
||||
if (actionNodeValues.result.isSuccess) {
|
||||
if (actionNodeValues.oldNode!= null && actionNodeValues.newNode != null)
|
||||
mListNodesFragment?.updateNode(actionNodeValues.oldNode, actionNodeValues.newNode)
|
||||
mListNodesFragment?.updateNodes(actionNodeValues.oldNodes, actionNodeValues.newNodes)
|
||||
}
|
||||
finishNodeAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -809,16 +761,12 @@ class GroupActivity : LockingActivity(),
|
||||
runOnUiThread {
|
||||
if (actionNodeValues.result.isSuccess) {
|
||||
|
||||
// If the action register the position, use it to remove the entry view
|
||||
val positionNode = actionNodeValues.result.data?.getInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY)
|
||||
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB
|
||||
&& positionNode != null) {
|
||||
mListNodesFragment?.removeNodeAt(positionNode)
|
||||
// Rebuold all the list the avoid bug when delete node from db sort
|
||||
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB) {
|
||||
mListNodesFragment?.rebuildList()
|
||||
} else {
|
||||
// Use the old Node that was the entry unchanged with the old parent
|
||||
actionNodeValues.oldNode?.let { oldNode ->
|
||||
mListNodesFragment?.removeNode(oldNode)
|
||||
}
|
||||
// Use the old Nodes / entries unchanged with the old parent
|
||||
mListNodesFragment?.removeNodes(actionNodeValues.oldNodes)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
fun addNodes(newNodes: List<NodeVersioned>) {
|
||||
mAdapter?.addNodes(newNodes)
|
||||
}
|
||||
|
||||
fun updateNode(oldNode: NodeVersioned, newNode: NodeVersioned? = null) {
|
||||
mAdapter?.updateNode(oldNode, newNode ?: oldNode)
|
||||
}
|
||||
|
||||
fun updateNodes(oldNodes: List<NodeVersioned>, newNodes: List<NodeVersioned>) {
|
||||
mAdapter?.updateNodes(oldNodes, newNodes)
|
||||
}
|
||||
|
||||
fun removeNode(pwNode: NodeVersioned) {
|
||||
mAdapter?.removeNode(pwNode)
|
||||
}
|
||||
|
||||
fun removeNodes(nodes: List<NodeVersioned>) {
|
||||
mAdapter?.removeNodes(nodes)
|
||||
}
|
||||
|
||||
fun removeNodeAt(position: Int) {
|
||||
mAdapter?.removeNodeAt(position)
|
||||
}
|
||||
|
||||
fun removeNodesAt(positions: IntArray) {
|
||||
mAdapter?.removeNodesAt(positions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback listener to redefine to do an action when a node is click
|
||||
*/
|
||||
|
||||
@@ -156,6 +156,14 @@ class NodeAdapter
|
||||
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
|
||||
* @param node Node to delete
|
||||
@@ -164,6 +172,16 @@ class NodeAdapter
|
||||
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
|
||||
*/
|
||||
@@ -173,6 +191,18 @@ class NodeAdapter
|
||||
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
|
||||
* @param oldNode Node before the update
|
||||
@@ -185,6 +215,20 @@ class NodeAdapter
|
||||
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) {
|
||||
notifyItemChanged(nodeSortedList.indexOf(node))
|
||||
}
|
||||
|
||||
@@ -45,8 +45,4 @@ abstract class ActionNodeDatabaseRunnable(
|
||||
|
||||
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.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
|
||||
class AddEntryRunnable constructor(
|
||||
context: FragmentActivity,
|
||||
@@ -45,6 +46,10 @@ class AddEntryRunnable constructor(
|
||||
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 com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
|
||||
class AddGroupRunnable constructor(
|
||||
context: FragmentActivity,
|
||||
@@ -42,6 +43,10 @@ class AddGroupRunnable constructor(
|
||||
if (!result.isSuccess) {
|
||||
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
|
||||
* - Add : @param oldNode NULL, @param newNode CreatedNode
|
||||
* - Copy : @param oldNode NodeToCopy, @param newNode NodeCopied
|
||||
* - Delete : @param oldNode NodeToDelete, @param NULL
|
||||
* - Move : @param oldNode NULL, @param NodeToMove
|
||||
* - Update : @param oldNode NodeToUpdate, @param NodeUpdated
|
||||
* - Add : @param oldNodes empty, @param newNodes CreatedNodes
|
||||
* - Copy : @param oldNodes NodesToCopy, @param newNodes NodesCopied
|
||||
* - Delete : @param oldNodes NodesToDelete, @param newNodes empty
|
||||
* - Move : @param oldNodes empty, @param newNodes NodesToMove
|
||||
* - 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 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 com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
|
||||
class UpdateEntryRunnable constructor(
|
||||
context: FragmentActivity,
|
||||
@@ -55,6 +56,11 @@ class UpdateEntryRunnable constructor(
|
||||
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 com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
|
||||
class UpdateGroupRunnable constructor(
|
||||
context: FragmentActivity,
|
||||
@@ -46,6 +47,11 @@ class UpdateGroupRunnable constructor(
|
||||
// If we fail to save, back out changes to global structure
|
||||
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
|
||||
get() {
|
||||
parent?.getChildren(true)?.let { children ->
|
||||
for ((i, child) in children.withIndex()) {
|
||||
if (child == this)
|
||||
return i
|
||||
children.forEachIndexed { index, nodeVersioned ->
|
||||
if (nodeVersioned == this)
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
|
||||
Reference in New Issue
Block a user