Skip to content

Commit

Permalink
Patch to introduce cross-window copy & paste.
Browse files Browse the repository at this point in the history
I wanted to be able to copy and paste song segments between windows so
I thought I would investigate adding this to TuxGuitar in support of
this awesome software.

=== This patch required: ===

 * Making the model serializable so that it could be sent "across the
   wire"

 * Making part of the graphics model (Rectangles/Points/Dimensions)
   Serializable

 * Changing the Transferable abstract to inherit from
   java.awt.datatransfer.Transferable, and changing the
   MeasureTransferable to implement that interface.

 * MeasureTransferable also had needed to be attachable/detachable to
   the TablatureEditor, and PasteMeasureAction needs to be aware of
   that.

 * Refactoring of TGFactory / abstract class instatiation, to concrete
   class instantiation to avoid closing in the hidden variable this$0,
   which causes the serialization to fail. (And who says java has no
   closures?) :/ This should also improve debugging, as classes will
   have their own name rather than eg: TGFactory$0.  This also meant
   making the whole model concrete rather than abstract classes. As
   best I can tell, this didnt change the semantics (as we were in
   fact just creating non specialized anonymous instances of those
   same classes.

=== Places to look for bugs / future improvements ===

 * I didnt investigate the graphics model heavily, so it is possible I
   missed something that needs to be serialized there.

 * Its possible I overlooked something (or some theoretical gain) in
   moving from abstract classes in the model to concrete classes.

 * Test Cases
  • Loading branch information
bobbysmith007 committed Sep 14, 2010
1 parent 29ead04 commit f5dd0be
Show file tree
Hide file tree
Showing 37 changed files with 125 additions and 129 deletions.
Expand Up @@ -135,8 +135,10 @@ protected void pasteMeasures(int pasteMode, int pasteCount){
if( pasteMode > 0 && pasteCount > 0 ){
Transferable transferable = getEditor().getClipBoard().getTransferable();
if(transferable instanceof MeasureTransferable){
((MeasureTransferable)transferable).setTransferType( pasteMode );
((MeasureTransferable)transferable).setPasteCount( pasteCount );
MeasureTransferable meas = ((MeasureTransferable)transferable);
meas.attach(getEditor());
meas.setTransferType( pasteMode );
meas.setPasteCount( pasteCount );

transferable.insertTransfer();

Expand Down
31 changes: 19 additions & 12 deletions src/org/herac/tuxguitar/app/clipboard/ClipBoard.java
Expand Up @@ -5,36 +5,43 @@
* Window - Preferences - Java - Code Style - Code Templates
*/
package org.herac.tuxguitar.app.clipboard;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;



/**
* @author julian
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class ClipBoard {
private Transferable transferable;

public ClipBoard(){
this.transferable = null;
}

public void addTransferable(Transferable transferable){
this.transferable = transferable;
public class ClipBoard{
public ClipBoard(){}
public void addTransferable(final Transferable transferable){
Clipboard sysclip = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
sysclip.setContents(transferable, null);
}

public Transferable getTransferable(){
return this.transferable;
Clipboard sysclip = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
try {
return (Transferable) java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().getData(MeasureTransferable.Measure);
}
catch (UnsupportedFlavorException e){ e.printStackTrace(); } // TODO Auto-generated catch block
catch (IOException e){ e.printStackTrace(); }// TODO Auto-generated catch block
return null;
}

public void insertTransfer() throws CannotInsertTransferException{
if(this.isEmpty()){
throw new CannotInsertTransferException();
}
this.transferable.insertTransfer();
this.getTransferable().insertTransfer();
}

public boolean isEmpty(){
return (this.transferable == null);
return (this.getTransferable() == null);
}
}
43 changes: 42 additions & 1 deletion src/org/herac/tuxguitar/app/clipboard/MeasureTransferable.java
Expand Up @@ -6,6 +6,9 @@
*/
package org.herac.tuxguitar.app.clipboard;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Iterator;

import org.herac.tuxguitar.app.TuxGuitar;
Expand All @@ -22,7 +25,7 @@
*
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
*/
public class MeasureTransferable implements Transferable {
public class MeasureTransferable implements Transferable, java.io.Serializable {
public static final int TRANSFER_TYPE_REPLACE = 1;
public static final int TRANSFER_TYPE_INSERT = 2;

Expand Down Expand Up @@ -127,4 +130,42 @@ private void skipMarkers(TGSongSegment segment){
header.setMarker(null);
}
}

public static DataFlavor Measure = new DataFlavor(MeasureTransferable.class, "A tux guitar transferable measure");
public static DataFlavor[] Flavors = new DataFlavor[]{Measure};

@Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
// TODO Auto-generated method stub
if(flavor.match(Measure)) return this;
else throw new UnsupportedFlavorException(flavor);
}

@Override
public DataFlavor[] getTransferDataFlavors() {
// TODO Auto-generated method stub
return Flavors;
}

@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.match(Measure);
}

// This function detaches data from the editor environment so that it can be sent "across the wire" to another java process
public void detach(){
this.tablatureEditor = null;
}
public void attach(TablatureEditor ed){
this.tablatureEditor = ed;
}
public static boolean onlyonce = false;
private void writeObject(java.io.ObjectOutputStream out) throws IOException{
this.detach();
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{in.defaultReadObject();};

}
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/app/clipboard/Transferable.java
Expand Up @@ -12,7 +12,7 @@
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public interface Transferable {
public interface Transferable extends java.awt.datatransfer.Transferable {

public void insertTransfer()throws CannotInsertTransferException;

Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/graphics/TGDimension.java
@@ -1,6 +1,6 @@
package org.herac.tuxguitar.graphics;

public class TGDimension {
public class TGDimension implements java.io.Serializable {

private int width;
private int height;
Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/graphics/TGPoint.java
@@ -1,6 +1,6 @@
package org.herac.tuxguitar.graphics;

public class TGPoint {
public class TGPoint implements java.io.Serializable {

private int x;
private int y;
Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/graphics/TGRectangle.java
@@ -1,6 +1,6 @@
package org.herac.tuxguitar.graphics;

public class TGRectangle {
public class TGRectangle implements java.io.Serializable {

private TGPoint location;
private TGDimension size;
Expand Down
108 changes: 27 additions & 81 deletions src/org/herac/tuxguitar/song/factory/TGFactory.java
Expand Up @@ -31,164 +31,110 @@
public class TGFactory {

public TGSong newSong(){
return new TGSong() {
//TGSong Implementation
};
return new TGSong();
}

public TGLyric newLyric(){
return new TGLyric(){
//TGLyric Implementation
};
return new TGLyric();
}

public TGMarker newMarker(){
return new TGMarker(this){
//TGMarker Implementation
};
return new TGMarker(this);
}

public TGChord newChord(int length){
return new TGChord(length){
//TGChord Implementation
};
return new TGChord(length);
}

public TGScale newScale(){
return new TGScale(){
//TGScale Implementation
};
return new TGScale();
}

public TGColor newColor(){
return new TGColor(){
//TGColor Implementation
};
return new TGColor();
}

public TGDuration newDuration(){
return new TGDuration(this){
//TGDuration Implementation
};
return new TGDuration(this);
}

public TGDivisionType newDivisionType(){
return new TGDivisionType(){
//TGDivisionType Implementation
};
return new TGDivisionType();
}

public TGTimeSignature newTimeSignature(){
return new TGTimeSignature(this){
//TGTimeSignature Implementation
};
return new TGTimeSignature(this);
}

public TGTempo newTempo(){
return new TGTempo(){
//TGTempo Implementation
};
return new TGTempo();
}

public TGChannel newChannel(){
return new TGChannel(){
//TGChannel Implementation
};
return new TGChannel();
}

public TGTrack newTrack(){
return new TGTrack(this){
//TGTrack Implementation
};
return new TGTrack(this);
}

public TGMeasureHeader newHeader(){
return new TGMeasureHeader(this){
//TGMeasureHeader Implementation
};
return new TGMeasureHeader(this);
}

public TGMeasure newMeasure(TGMeasureHeader header){
return new TGMeasure(header){
//TGMeasure Implementation
};
return new TGMeasure(header);
}

public TGBeat newBeat(){
return new TGBeat(this){
//TGBeat Implementation
};
return new TGBeat(this);
}

public TGVoice newVoice(int index){
return new TGVoice(this, index){
//TGVoice Implementation
};
return new TGVoice(this, index);
}

public TGNote newNote(){
return new TGNote(this){
//TGNote Implementation
};
return new TGNote(this);
}

public TGString newString(){
return new TGString(){
//TGString Implementation
};
return new TGString();
}

public TGStroke newStroke(){
return new TGStroke(){
//TGString Implementation
};
return new TGStroke();
}

public TGText newText(){
return new TGText(){
//TGString Implementation
};
return new TGText();
}

public TGNoteEffect newEffect(){
return new TGNoteEffect(){
//TGNoteEffect Implementation
};
return new TGNoteEffect();
}

public TGEffectBend newEffectBend(){
return new TGEffectBend(){
//TGEffectBend Implementation
};
return new TGEffectBend();
}

public TGEffectTremoloBar newEffectTremoloBar(){
return new TGEffectTremoloBar(){
//TGEffectTremoloBar Implementation
};
return new TGEffectTremoloBar();
}

public TGEffectGrace newEffectGrace(){
return new TGEffectGrace(){
//TGEffectGrace Implementation
};
return new TGEffectGrace();
}

public TGEffectHarmonic newEffectHarmonic(){
return new TGEffectHarmonic(){
//TGEffectHarmonic Implementation
};
return new TGEffectHarmonic();
}

public TGEffectTrill newEffectTrill(){
return new TGEffectTrill(this){
//TGEffectTrill Implementation
};
return new TGEffectTrill(this);
}

public TGEffectTremoloPicking newEffectTremoloPicking(){
return new TGEffectTremoloPicking(this){
//TGEffectTremoloPicking Implementation
};
return new TGEffectTremoloPicking(this);
}
}
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/song/helpers/TGSongSegment.java
Expand Up @@ -6,7 +6,7 @@
import org.herac.tuxguitar.song.factory.TGFactory;
import org.herac.tuxguitar.song.models.TGMeasureHeader;

public class TGSongSegment {
public class TGSongSegment implements java.io.Serializable {
private List headers;
private List tracks;

Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/song/helpers/TGTrackSegment.java
Expand Up @@ -7,7 +7,7 @@
import org.herac.tuxguitar.song.models.TGMeasure;
import org.herac.tuxguitar.song.models.TGMeasureHeader;

public class TGTrackSegment {
public class TGTrackSegment implements java.io.Serializable{
private int track;
private List measures;

Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/song/models/TGBeat.java
Expand Up @@ -13,7 +13,7 @@
*
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
*/
public abstract class TGBeat {
public class TGBeat implements java.io.Serializable {

public static final int MAX_VOICES = 2;

Expand Down
2 changes: 1 addition & 1 deletion src/org/herac/tuxguitar/song/models/TGChannel.java
Expand Up @@ -2,7 +2,7 @@

import org.herac.tuxguitar.song.factory.TGFactory;

public abstract class TGChannel {
public class TGChannel implements java.io.Serializable {
public static final short DEFAULT_PERCUSSION_CHANNEL = 9;

public static final short DEFAULT_INSTRUMENT = 25;
Expand Down

0 comments on commit f5dd0be

Please sign in to comment.