- #1649 Moving SWF files (and bundles) up and down
- Moving tags up and down
(context menuitem + ALT up/down shortcut)
This commit is contained in:
Jindra Petřík
2022-11-10 18:26:55 +01:00
parent e6bd00d2a0
commit c1a998b117
10 changed files with 269 additions and 21 deletions

View File

@@ -12,6 +12,8 @@ All notable changes to this project will be documented in this file.
- Move tag with dependencies
- Copy/Move tag operation has select position dialog
- Select position dialog has target file in its title
- [#1649] Moving SWF files (and bundles) up and down (comtext menuitem + ALT up/down shortcut)
- Moving tags up and down (context menuitem + ALT up/down shortcut)
### Fixed
- Exception when bundle selected
@@ -2538,6 +2540,7 @@ All notable changes to this project will be documented in this file.
[alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9
[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8
[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7
[#1649]: https://www.free-decompiler.com/flash/issues/1649
[#1863]: https://www.free-decompiler.com/flash/issues/1863
[#1414]: https://www.free-decompiler.com/flash/issues/1414
[#1755]: https://www.free-decompiler.com/flash/issues/1755

View File

@@ -399,6 +399,63 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private boolean clipboardCut = false;
private void handleTreeKeyReleased(KeyEvent e) {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
if ((e.getKeyCode() == KeyEvent.VK_UP
|| e.getKeyCode() == KeyEvent.VK_DOWN)
&& e.isAltDown() && !e.isControlDown() && !e.isShiftDown()) {
TreePath paths[] = tree.getSelectionPaths();
if (paths == null || paths.length != 1) {
return;
}
TreeItem item = (TreeItem) paths[0].getLastPathComponent();
if (e.getKeyCode() == KeyEvent.VK_UP) {
contextPopupMenu.moveUpDown(item, true);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
contextPopupMenu.moveUpDown(item, false);
}
}
}
public void moveSwfListUpDown(TreeItem item, boolean up) {
SWFList swfList = null;
if (item instanceof SWF) {
SWF swf = (SWF) item;
if (swf.swfList != null && !swf.swfList.isBundle() && swf.swfList.size() == 1) {
swfList = swf.swfList;
} else {
return;
}
} else if (item instanceof SWFList) {
swfList = (SWFList) item;
} else {
return;
}
int index = swfs.indexOf(swfList);
List<List<String>> expandedTagTree = View.getExpandedNodes(tagTree);
List<List<String>> expandedTagListTree = View.getExpandedNodes(tagListTree);
if (up) {
if (index <= 0) {
return;
}
swfs.move(index, index - 1);
} else {
if (index < 0 || index >= swfs.size() - 1) {
return;
}
swfs.move(index, index + 2);
}
View.expandTreeNodes(tagTree, expandedTagTree);
View.expandTreeNodes(tagListTree, expandedTagListTree);
TreePath path = getCurrentTree().getModel().getTreePath(item);
getCurrentTree().setSelectionPath(path);
getCurrentTree().scrollPathToVisible(path);
repaintTree();
}
private void handleTreeKeyPressed(KeyEvent e) {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
if ((e.getKeyCode() == 'C' || e.getKeyCode() == 'X') && (e.isControlDown())) {
@@ -943,6 +1000,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
showContentPanelCard(WELCOME_PANEL);
tagTree.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleTreeKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
if ((e.getKeyCode() == 'F') && (e.isControlDown())) {
@@ -984,6 +1046,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
});
tagListTree.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleTreeKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
handleTreeKeyPressed(e);

View File

@@ -22,5 +22,5 @@ package com.jpexs.decompiler.flash.gui.helpers;
*/
public enum CollectionChangedAction {
ADD, REMOVE, RESET
ADD, REMOVE, RESET, MOVE
}

View File

@@ -49,6 +49,14 @@ public class CollectionChangedEvent<E> {
break;
}
}
public CollectionChangedEvent(CollectionChangedAction action, E oldItem, E newItem, int oldIndex, int newIndex) {
this.action = action;
this.oldItem = oldItem;
this.newItem = newItem;
this.oldIndex = oldIndex;
this.newIndex = newIndex;
}
public CollectionChangedAction getAction() {
return action;

View File

@@ -79,6 +79,55 @@ public class ObservableList<E> implements List<E> {
return false;
}
/** * Move item to desired position.0 A
1 B
2 C
3 D
4 E
move(1, 3)
0 A
1 C
2 B
3 D
4 E
move(3, 1)
0 A
1 D
2 B
3 C
4 E
* @param oldIndex
* @param newIndex
* @return
*/
public boolean move(int oldIndex, int newIndex) {
if (oldIndex == newIndex) {
return true;
}
if (oldIndex < 0 || oldIndex >= size()) {
throw new ArrayIndexOutOfBoundsException(oldIndex);
}
if (newIndex < 0 || newIndex > size()) {
throw new ArrayIndexOutOfBoundsException(newIndex);
}
E item = list.remove(oldIndex);
if (newIndex > oldIndex) {
list.add(newIndex - 1, item);
} else {
list.add(newIndex, item);
}
fireCollectionChanged(new CollectionChangedEvent<>(CollectionChangedAction.MOVE, item, item, oldIndex, newIndex));
return true;
}
public boolean move(E item, int newIndex) {
return move(indexOf(item), newIndex);
}
@Override
public boolean containsAll(Collection<?> c) {

View File

@@ -945,4 +945,6 @@ clipboard.items = %count% items
clipboard.clear = Clear the tag clipboard
#after 16.2.0
contextmenu.moveTagWithDependencies = Move tag with dependencies to
contextmenu.moveTagWithDependencies = Move tag with dependencies to
contextmenu.moveUp = Move up
contextmenu.moveDown = Move down

View File

@@ -917,4 +917,6 @@ clipboard.items = %count% polo\u017eek
clipboard.clear = Vy\u010distit tagovou schr\u00e1nku
#after 16.2.0
contextmenu.moveTagWithDependencies = P\u0159esunout tag se z\u00e1vislostmi do
contextmenu.moveTagWithDependencies = P\u0159esunout tag se z\u00e1vislostmi do
contextmenu.moveUp = Posunout nahoru
contextmenu.moveDown = Posunout dol\u016f

View File

@@ -175,7 +175,8 @@ public class TagListTreeModel extends AbstractTagTreeModel {
@Override
public void updateSwfs(CollectionChangedEvent e) {
if (e.getAction() != CollectionChangedAction.ADD) {
if (e.getAction() != CollectionChangedAction.ADD &&
e.getAction() != CollectionChangedAction.MOVE) {
List<SWF> toRemove = new ArrayList<>();
for (SWF swf : swfHeaders.keySet()) {
SWF swf2 = swf.getRootSwf();
@@ -200,6 +201,12 @@ public class TagListTreeModel extends AbstractTagTreeModel {
fireTreeNodesRemoved(new TreeModelEvent(this, rootPath, new int[]{e.getOldIndex()}, new Object[]{e.getOldItem()}));
break;
}
/*case MOVE: {
TreePath rootPath = new TreePath(new Object[]{root});
fireTreeNodesRemoved(new TreeModelEvent(this, rootPath, new int[]{e.getOldIndex()}, new Object[]{e.getOldItem()}));
fireTreeNodesInserted(new TreeModelEvent(this, rootPath, new int[]{e.getNewIndex()}, new Object[]{e.getNewItem()}));
break;
}*/
default:
fireTreeStructureChanged(new TreeModelEvent(this, new TreePath(root)));
}

View File

@@ -169,7 +169,11 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenu moveTagToMenu;
private JMenu moveTagToWithDependenciesMenu;
private JMenuItem moveUpMenuItem;
private JMenuItem moveDownMenuItem;
private JMenu copyTagToMenu;
private JMenu copyTagToWithDependenciesMenu;
@@ -207,7 +211,7 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenuItem addFramesAfterMenuItem;
private static final int KIND_MOVETO = 0;
private static final int KIND_MOVETODEPS = 1;
private static final int KIND_MOVETODEPS = 1;
private static final int KIND_COPYTO = 2;
private static final int KIND_COPYTODEPS = 3;
@@ -357,7 +361,16 @@ public class TagTreeContextMenu extends JPopupMenu {
moveTagToWithDependenciesMenu.setIcon(View.getIcon("move16"));
add(moveTagToWithDependenciesMenu);
moveUpMenuItem = new JMenuItem(mainPanel.translate("contextmenu.moveUp")+" (ALT + UP)");
moveUpMenuItem.setIcon(View.getIcon("arrowup16"));
moveUpMenuItem.addActionListener(this::moveUpActionPerformed);
add(moveUpMenuItem);
moveDownMenuItem = new JMenuItem(mainPanel.translate("contextmenu.moveDown") + " (ALT + DOWN)");
moveDownMenuItem.setIcon(View.getIcon("arrowdown16"));
moveDownMenuItem.addActionListener(this::moveDownActionPerformed);
add(moveDownMenuItem);
copyTagToMenu = new JMenu(mainPanel.translate("contextmenu.copyTag"));
copyTagToMenu.setIcon(View.getIcon("copy16"));
add(copyTagToMenu);
@@ -673,6 +686,8 @@ public class TagTreeContextMenu extends JPopupMenu {
addTagAfterMenu.setVisible(false);
moveTagToMenu.setVisible(false);
moveTagToWithDependenciesMenu.setVisible(false);
moveUpMenuItem.setVisible(false);
moveDownMenuItem.setVisible(false);
copyTagToMenu.setVisible(false);
copyTagToWithDependenciesMenu.setVisible(false);
cutTagToClipboardMenuItem.setVisible(false);
@@ -854,6 +869,22 @@ public class TagTreeContextMenu extends JPopupMenu {
pasteBeforeMenuItem.setVisible(true);
}
}
if ((firstItem instanceof Tag) && (getTree() == mainPanel.tagListTree)) {
moveUpMenuItem.setVisible(true);
moveDownMenuItem.setVisible(true);
}
if (firstItem instanceof SWF) {
SWF firstSwf = (SWF) firstItem;
if (firstSwf.swfList != null && !firstSwf.swfList.isBundle() && firstSwf.swfList.size() == 1) {
moveUpMenuItem.setVisible(true);
moveDownMenuItem.setVisible(true);
}
}
if (firstItem instanceof SWFList) {
moveUpMenuItem.setVisible(true);
moveDownMenuItem.setVisible(true);
}
}
moveTagToMenu.removeAll();
@@ -1210,7 +1241,7 @@ public class TagTreeContextMenu extends JPopupMenu {
t.setTimelined(timelined);
timelined.resetTimeline();
timelined.setFrameCount(timelined.getTimeline().getFrameCount());
timelined.setFrameCount(timelined.getTimeline().getFrameCount());
}
swf.updateCharacters();
@@ -1296,7 +1327,7 @@ public class TagTreeContextMenu extends JPopupMenu {
tag.setSwf(targetSwf, true);
tag.setTimelined(timelined);
checkUniqueCharacterId(tag);
int positionInt = position == null ? timelined.getTags().size() : timelined.indexOfTag(position);
int positionInt = position == null ? timelined.getTags().size() : timelined.indexOfTag(position);
timelined.addTag(positionInt, tag);
targetSwf.updateCharacters();
tag.setModified(true);
@@ -1312,9 +1343,9 @@ public class TagTreeContextMenu extends JPopupMenu {
targetSwf.updateCharacters();
sourceSwf.resetTimelines(sourceSwf);
targetSwf.resetTimelines(targetSwf);
timelined.setFrameCount(timelined.getTimeline().getFrameCount());
mainPanel.refreshTree(new SWF[]{sourceSwf, targetSwf});
}
@@ -1325,29 +1356,29 @@ public class TagTreeContextMenu extends JPopupMenu {
}
Tag position = selectPositionDialog.getSelectedTag();
Timelined timelined = selectPositionDialog.getSelectedTimelined();
copyOrMoveTags(new LinkedHashSet<TreeItem>(items), false, timelined, position);
copyOrMoveTags(new LinkedHashSet<TreeItem>(items), false, timelined, position);
}
private void copyTagWithDependenciesToActionPerformed(ActionEvent evt, List<TreeItem> items, SWF targetSwf) {
private void copyTagWithDependenciesToActionPerformed(ActionEvent evt, List<TreeItem> items, SWF targetSwf) {
SelectTagPositionDialog selectPositionDialog = new SelectTagPositionDialog(mainPanel.getMainFrame().getWindow(), targetSwf, true);
if (selectPositionDialog.showDialog() != AppDialog.OK_OPTION) {
return;
}
Tag position = selectPositionDialog.getSelectedTag();
Timelined timelined = selectPositionDialog.getSelectedTimelined();
copyOrMoveTags(getDependenciesSet(items), false, timelined, position);
copyOrMoveTags(getDependenciesSet(items), false, timelined, position);
}
private void moveTagWithDependenciesToActionPerformed(ActionEvent evt, List<TreeItem> items, SWF targetSwf) {
private void moveTagWithDependenciesToActionPerformed(ActionEvent evt, List<TreeItem> items, SWF targetSwf) {
SelectTagPositionDialog selectPositionDialog = new SelectTagPositionDialog(mainPanel.getMainFrame().getWindow(), targetSwf, true);
if (selectPositionDialog.showDialog() != AppDialog.OK_OPTION) {
return;
}
Tag position = selectPositionDialog.getSelectedTag();
Timelined timelined = selectPositionDialog.getSelectedTimelined();
copyOrMoveTags(getDependenciesSet(items), true, timelined, position);
copyOrMoveTags(getDependenciesSet(items), true, timelined, position);
}
private void openSwfInsideActionPerformed(ActionEvent evt) {
@@ -2558,7 +2589,7 @@ public class TagTreeContextMenu extends JPopupMenu {
break;
case KIND_MOVETODEPS:
moveTagWithDependenciesToActionPerformed(ae, items, targetSwf);
break;
break;
case KIND_COPYTO:
copyTagToActionPerformed(ae, items, targetSwf);
break;
@@ -2856,4 +2887,76 @@ public class TagTreeContextMenu extends JPopupMenu {
mainPanel.importSymbolClass(swf);
}
public void moveUpActionPerformed(ActionEvent evt) {
moveUpDown(getTree().getCurrentTreeItem(), true);
}
public void moveDownActionPerformed(ActionEvent evt) {
moveUpDown(getTree().getCurrentTreeItem(), false);
}
public void moveUpDown(TreeItem item, boolean up) {
if ((item instanceof SWF) || (item instanceof SWFList)) {
mainPanel.moveSwfListUpDown(item, up);
return;
}
if (!(item instanceof Tag)) {
return;
}
if (getTree() != mainPanel.tagListTree) {
return;
}
Set<TreeItem> itemsToMove = new HashSet<>();
itemsToMove.add(item);
Tag tag = (Tag) item;
int index = tag.getTimelined().indexOfTag(tag);
Tag position = null;
Timelined timelined = null;
ReadOnlyTagList tags = tag.getTimelined().getTags();
if (up) {
if (index == 0) {
if (tag.getTimelined() instanceof SWF) {
return;
}
//move one level UP
position = (DefineSpriteTag) tag.getTimelined();
} else {
index = tag.getTimelined().indexOfTag(tag);
index--;
position = tag.getTimelined().getTags().get(index);
}
timelined = position.getTimelined();
} else {
if (index == tags.size() - 1) {
if (tag.getTimelined() instanceof SWF) {
return;
}
timelined = ((DefineSpriteTag) tag.getTimelined()).getTimelined();
index = timelined.getTags().indexOf((DefineSpriteTag) tag.getTimelined());
index++;
if (index >= timelined.getTags().size()) {
position = null;
} else {
position = timelined.getTags().get(index);
}
} else {
timelined = tag.getTimelined();
index = timelined.indexOfTag(tag);
index += 2;
if (index >= timelined.getTags().size()) {
position = null;
} else {
position = timelined.getTags().get(index);
}
}
}
copyOrMoveTags(itemsToMove, true, timelined, position);
TreePath path = getTree().getModel().getTreePath(item);
getTree().setSelectionPath(path);
getTree().scrollPathToVisible(path);
mainPanel.repaintTree();
}
}

View File

@@ -109,7 +109,8 @@ public class TagTreeModel extends AbstractTagTreeModel {
}
public void updateSwfs(CollectionChangedEvent e) {
if (e.getAction() != CollectionChangedAction.ADD) {
if (e.getAction() != CollectionChangedAction.ADD &&
e.getAction() != CollectionChangedAction.MOVE) {
List<SWF> toRemove = new ArrayList<>();
for (SWF swf : swfInfos.keySet()) {
SWF swf2 = swf.getRootSwf();
@@ -134,6 +135,12 @@ public class TagTreeModel extends AbstractTagTreeModel {
fireTreeNodesRemoved(new TreeModelEvent(this, rootPath, new int[]{e.getOldIndex()}, new Object[]{e.getOldItem()}));
break;
}
/*case MOVE: {
TreePath rootPath = new TreePath(new Object[]{root});
fireTreeNodesRemoved(new TreeModelEvent(this, rootPath, new int[]{e.getOldIndex()}, new Object[]{e.getOldItem()}));
fireTreeNodesInserted(new TreeModelEvent(this, rootPath, new int[]{e.getNewIndex()}, new Object[]{e.getNewItem()}));
break;
}*/
default:
fireTreeStructureChanged(new TreeModelEvent(this, new TreePath(root)));
}