Skip to content

Commit

Permalink
stupid implementation of ctrl-z - just snapshoting whole project on e…
Browse files Browse the repository at this point in the history
…very action. should probably do with diff and child field change listeners...
  • Loading branch information
klesun authored and klesun committed Jan 10, 2016
1 parent 499ff4e commit 844cb77
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 17 deletions.
16 changes: 4 additions & 12 deletions src/org/klesun_model/Explain.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.shmidusic.stuff.tools.Logger;

import javax.xml.transform.Result;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;
Expand Down Expand Up @@ -76,13 +77,9 @@ public Explain<C> whenSuccess(Consumer<C> lambda) {
return ifSuccess(c -> { lambda.accept(c); return this; });
}

public Explain<C> whenFailure(Runnable onFailure) {
if (!this.isSuccess()) {
onFailure.run();
}
return this;

}
public <T> Explain<T> map(Function<C, T> mapLambda) {
return ifSuccess(result -> new Explain<T>(mapLambda.apply(result)));
}

public Explain<C> runIfSuccess(Runnable lambda) { return whenSuccess(r -> lambda.run()); }

Expand Down Expand Up @@ -114,9 +111,4 @@ public static <T, R> Function<T, Explain<R>> mkPred(Predicate<T> pred, Function<
? new Explain<>(func.apply(e))
: new Explain<>(false, "lox");
}

public Explain<C> whileIf(Supplier<Boolean> cond, Function<C, Explain<C>> iteration)
{
return cond.get() ? iteration.apply(this.data).whileIf(cond, iteration) : this;
}
}
63 changes: 63 additions & 0 deletions src/org/klesun_model/SnapshotStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.klesun_model;

// this class stores history to undo/redo
// for now, i plan woodenly just store SheetMusic snapshot
// after each handled event (if it differs from previous snapshot)

import com.google.common.collect.EvictingQueue;
import org.json.JSONObject;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.stream.StreamSupport;

public class SnapshotStorage
{
/** @TODO: storing snapshots is obviously not efficient (especially with the json string generation)
* hang change listeners to fields of Models and store diff instead of snapshots */
final private Deque<JSONObject> snapshots = new ArrayDeque<>();
final private Deque<JSONObject> redoSnapshots = new ArrayDeque<>();

public void add(JSONObject snapshot)
{
if (snapshots.isEmpty() || !areEqual(snapshot, snapshots.peekLast())) {

snapshots.add(snapshot);
redoSnapshots.clear();

if (snapshots.size() > 20) {
snapshots.removeFirst();
}
}
}

public Explain<JSONObject> undo()
{
if (snapshots.size() >= 2) {
JSONObject current = snapshots.pollLast();
redoSnapshots.add(current);

return new Explain<>(snapshots.peekLast());
} else {
return new Explain<>(false, "Here History Starts");
}
}

public Explain<JSONObject> redo()
{
if (redoSnapshots.size() >= 2) {
JSONObject current = redoSnapshots.pollLast();
snapshots.add(current);

return new Explain<>(redoSnapshots.peekLast());
} else {
return new Explain<>(false, "Here History Ends");
}
}

// probably will be faster if we assert without string generation...
private static boolean areEqual(JSONObject a, JSONObject b) {
return a.toString().equals(b.toString());
}
}
13 changes: 12 additions & 1 deletion src/org/shmidusic/MainPanel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.shmidusic;

import org.klesun_model.Explain;
import org.klesun_model.SnapshotStorage;
import org.shmidusic.sheet_music.staff.Staff;
import org.shmidusic.sheet_music.SheetMusic;
import org.shmidusic.sheet_music.SheetMusicComponent;
Expand All @@ -21,6 +23,7 @@ final public class MainPanel extends JPanel {

public SheetMusicComponent sheetContainer = new SheetMusicComponent(new SheetMusic(), this);
public Scroll sheetScroll = new Scroll(sheetContainer);
final public SnapshotStorage snapshotStorage = new SnapshotStorage();

final private PianoLayoutPanel pianoLayoutPanel;
final private JLabel statusField = new JLabel("status text");
Expand Down Expand Up @@ -54,7 +57,7 @@ public void replaceSheetMusic(SheetMusic sheetMusic)
this.add(sheetScroll = new Scroll(sheetContainer), BorderLayout.CENTER);
sheetScroll.getVerticalScrollBar().setUnitIncrement(Staff.SISDISPLACE);
sheetContainer.requestFocus();
DumpReceiver.eventHandler = (StaffHandler) sheetContainer.getFocusedChild().getHandler();
DumpReceiver.eventHandler = sheetContainer.getFocusedChild().getHandler();
// removing stupid built-ins
InputMap im = sheetScroll.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke("UP"), "none");
Expand Down Expand Up @@ -92,5 +95,13 @@ private String getStatusText()

return result;
}

public Explain undo() {
return snapshotStorage.undo().map(SheetMusic::new).whenSuccess(this::replaceSheetMusic);
}

public Explain redo() {
return snapshotStorage.redo().map(SheetMusic::new).whenSuccess(this::replaceSheetMusic);
}
}

1 change: 1 addition & 0 deletions src/org/shmidusic/MajesticWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ private JMenuItem makeActionMenuItem(Combo key, ContextAction action, Class<? ex
if (context != null) {
Explain explain = action.redo(context);
if (explain.isSuccess()) {
shmidusicPanel.snapshotStorage.add(context.getModel().getJsonRepresentation());
updateMenuBar();
} else {
JOptionPane.showMessageDialog(this, explain.getExplanation());
Expand Down
6 changes: 6 additions & 0 deletions src/org/shmidusic/sheet_music/SheetMusic.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.shmidusic.sheet_music;

import org.json.JSONObject;
import org.klesun_model.AbstractModel;
import org.klesun_model.field.Arr;
import org.shmidusic.sheet_music.staff.Staff;
Expand All @@ -11,6 +12,11 @@ public class SheetMusic extends AbstractModel
{
public Arr<Staff> staffList = add("staffList", new ArrayList<>(), Staff.class);

public SheetMusic(JSONObject state) {
this();
reconstructFromJson(state);
}

public SheetMusic()
{
Staff staff = new Staff();
Expand Down
25 changes: 21 additions & 4 deletions src/org/shmidusic/sheet_music/SheetMusicComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;
Expand Down Expand Up @@ -57,13 +58,29 @@ public LinkedHashMap<Combo, ContextAction> getMyClassActionMap() {
.p(new Combo(ctrl, k.VK_I), mkFailableAction(FileProcessor::openMidi).setCaption("Open midi"))

.p(new Combo(ctrl, k.VK_E), mkFailableAction(FileProcessor::savePNG).setCaption("Export png"))
;

/** @debug */
.p(new Combo(ctrl, k.VK_Z), mkFailableAction(sm -> mainPanel.undo()).setCaption("Undo"))
.p(new Combo(ctrl, k.VK_Y), mkFailableAction(sm -> mainPanel.redo()).setCaption("Redo"))
;
}
public IComponent getContext() { return self; };
};
this.addKeyListener(Fp.onKey(e -> {
Explain result = handler.handleKey(new Combo(e));
if (!result.isSuccess() && !result.isImplicit()) {
this.addKeyListener(Fp.onKey(e ->
{
/** @TODO: same to menu */
Combo combo = new Combo(e);

Explain result = handler.handleKey(combo);
if (result.isSuccess()) {
// TODO: ctrl-z/ctrl-y probably should not be normal action at all!
if (!combo.equals(new Combo(KeyEvent.CTRL_MASK, KeyEvent.VK_Z)) &&
!combo.equals(new Combo(KeyEvent.CTRL_MASK, KeyEvent.VK_Y)))
{
mainPanel.snapshotStorage.add(sheetMusic.getJsonRepresentation());
}

} else if (!result.isImplicit()) {
JOptionPane.showMessageDialog(this, result.getExplanation());
}
}));
Expand Down

0 comments on commit 844cb77

Please sign in to comment.