package org.clothocad.tool.grapevine;
/*
Copyright (c) 2009 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS..
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import org.clothocore.api.core.Collector;
import org.clothocore.api.data.Attachment;
import org.clothocore.api.data.Factoid;
import org.clothocore.api.data.Note;
import org.clothocore.api.data.ObjBase;
import org.clothocore.api.data.ObjLink;
import org.clothocore.api.data.ObjType;
import org.clothocore.api.data.Person;
import org.clothocore.api.dnd.ObjBaseObserver;
import org.clothocore.api.dnd.RefreshEvent;
import org.clothocore.api.plugin.ClothoConnection;
import org.clothocore.api.plugin.ClothoConnection.ClothoQuery;
import org.clothocore.util.basic.ObjBasePopup;
import org.clothocad.wikieditorpanel.WikiEditorPanel;
import org.clothocore.api.data.Family;
import org.clothocore.api.data.Feature;
import org.clothocore.api.data.Strain;
import org.clothocore.util.basic.ImageSource;
import org.clothocore.util.buttons.TransparentButton;
import org.clothocore.util.misc.CommandHelp;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
/**
*
* @author J. Christopher Anderson
*/
public class NoteEditor extends JFrame {
public NoteEditor(Note note) {
super("Grapevine Note Editor");
_note = note;
setIconImage(ImageSource.getTinyLogo());
initComponents();
putInFactoids();
noteListener = new ObjBaseObserver() {
@Override
public void update(ObjBase obj, RefreshEvent evt) {
if(evt.isCondition(RefreshEvent.Condition.FACTOID_TO_NOTE)
|| evt.isCondition(RefreshEvent.Condition.NOTE_LINKED)
|| evt.isCondition(RefreshEvent.Condition.UPDATE_ALL)) {
putInFactoids();
}
if(evt.isCondition(RefreshEvent.Condition.NAME_CHANGED)
|| evt.isCondition(RefreshEvent.Condition.UPDATE_ALL)) {
noteTitleField.setText(_note.getName());
}
if(evt.isCondition(RefreshEvent.Condition.NOTE_LINKED)) {
putLinksToBiologicals();
}
}
};
_note.isRepresentedBy(noteListener, headerPanel);
}
public void initComponents() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel topPanel = new JPanel();
topPanel.setLayout( new BorderLayout() );
getContentPane().add( topPanel );
createHeader();
createMenuBar();
topPanel.add(headerPanel, BorderLayout.NORTH);
notesPanel = new JPanel();
notesPanel.setLayout(new BorderLayout());
JScrollPane noteScroller = new JScrollPane();
CommentScrollPanel = new ScrollablePanel();
noteScroller.setViewportView(CommentScrollPanel);
noteScroller.setWheelScrollingEnabled(true);
CommentScrollPanel.setLayout(new BoxLayout(CommentScrollPanel, BoxLayout.PAGE_AXIS));
CommentScrollPanel.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT);
CommentScrollPanel.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.NONE);
notesPanel.add(noteScroller);
topPanel.add(notesPanel, BorderLayout.CENTER);
setPreferredSize(new Dimension(550, 600));
pack();
addFactoid.requestFocus();
setVisible( true );
}
private void createHeader() {
headerPanel = new JPanel();
headerPanel.setLayout( new BorderLayout() );
headerPanel.setBackground(navyblue);
noteTitleField = new blueTextField(18) {
@Override
public void gainFocus() {
}
@Override
public void loseFocus() {
if(oldValue.equals(this.getText())) {
return;
}
oldValue = this.getText();
_note.changeName(oldValue);
}
@Override
public void dataUpdated() {
this.setText(_note.getName());
}
};
noteTitleField.setText(_note.getName());
headerPanel.add(noteTitleField, BorderLayout.NORTH);
noteWTEd = new WikiEditorPanel(this, _note.getWikiText());
noteWTEd.setHTMLMode();
headerPanel.add(noteWTEd, BorderLayout.CENTER);
Box newNoteFactBox = new Box(BoxLayout.X_AXIS);
headerPanel.add( newNoteFactBox, BorderLayout.SOUTH );
addFactoid = new JButton("Add new Factoid...");
addFactoid.setIcon(factoidIcon);
addFactoid.setBackground(navyblue);
addFactoid.setForeground(Color.WHITE);
addFactoid.setBorder(null);
addFactoid.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
_note.addObject(new Factoid("New factoid", Collector.getCurrentUser(), "", null));
}
});
new ObjBasePopup(addFactoid, _note);
newNoteFactBox.add(addFactoid);
newNoteFactBox.add(Box.createHorizontalStrut(13));
addSubNote = new JButton("Add new sub-note...");
addSubNote.setIcon(noteIcon);
addSubNote.setBackground(navyblue);
addSubNote.setForeground(Color.WHITE);
addSubNote.setBorder(null);
addSubNote.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
_note.addObject(new Note("New note", Collector.getCurrentUser(), null));
}
});
new ObjBasePopup(addSubNote, _note);
newNoteFactBox.add(addSubNote);
newNoteFactBox.add(Box.createHorizontalStrut(13));
addFeature = new JButton("Link to:");
addFeature.setBackground(navyblue);
addFeature.setForeground(Color.WHITE);
addFeature.setBorder(null);
addFeature.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
System.out.println("Create new one");
}
});
new ObjBasePopup(addFeature, _note);
newNoteFactBox.add(addFeature);
newNoteFactBox.add(Box.createHorizontalStrut(5));
featureTextBox = new JTextField("Type help for details");
featureTextBox.setFont(italFont);
featureTextBox.setToolTipText("Type feature, strain, or family name");
featureTextBox.setMaximumSize(new Dimension(90, 18));
featureTextBox.setBorder(blackline);
featureTextBox.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if(featureTextBox.getText().equals("Type help for details")) {
featureTextBox.setText("");
featureTextBox.setFont(regFont);
}
}
@Override
public void focusLost(FocusEvent e) {
if(featureTextBox.getText().equals("")) {
featureTextBox.setText("Type help for details");
featureTextBox.setFont(italFont);
return;
} else if(featureTextBox.getText().trim().equals("help")) {
JOptionPane.showMessageDialog(NoteEditor.this,
"Type the name of the Feature, Family, or Strain you wish to link.",
"Type in name",
JOptionPane.DEFAULT_OPTION);
featureTextBox.setText("Type help for details");
featureTextBox.setFont(italFont);
return;
}
processFeatureTextBox();
}
});
newNoteFactBox.add(featureTextBox);
newNoteFactBox.add(Box.createHorizontalStrut(5));
BioLinksBox = new Box(BoxLayout.X_AXIS);
newNoteFactBox.add(BioLinksBox);
new ObjBasePopup(newNoteFactBox, _note);
new ObjBasePopup(noteTitleField, _note);
}
private void processFeatureTextBox() {
String entry = featureTextBox.getText();
System.out.println("Processing " + entry);
Feature afeat = Feature.retrieveByName(entry);
if(afeat!=null) {
System.out.println("adding note to feature " + afeat.getName());
afeat.addObject(_note);
thingsToSave.add(afeat);
featureTextBox.setText("Type help for details");
featureTextBox.setFont(italFont);
return;
}
Strain astrain = Strain.retrieveByName(entry);
if(astrain!=null) {
System.out.println("adding note to strain " + astrain.getName());
astrain.addObject(_note);
thingsToSave.add(astrain);
featureTextBox.setText("Type help for details");
featureTextBox.setFont(italFont);
return;
}
Family afam = Family.retrieveByName(entry);
if(afam!=null) {
System.out.println("adding note to family " + afam.getName());
afam.addObject(_note);
thingsToSave.add(afam);
featureTextBox.setText("Type help for details");
featureTextBox.setFont(italFont);
return;
}
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
menuBar.setBackground(navyblue);
JMenu fileMenu = new JMenu();
fileMenu.setText("File");
fileMenu.setForeground(Color.WHITE);
menuBar.add(fileMenu);
JMenuItem newWindow = new JMenuItem();
newWindow.setText("New Note");
newWindow.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
newWindow.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
new NoteEditor(new Note("New note", Collector.getCurrentUser(), null));
}
});
fileMenu.add(newWindow);
JMenuItem openItem = new JMenuItem();
openItem.setText("Open My Notes");
openItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
openItem.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
launchListOfNotes(false);
}
});
fileMenu.add(openItem);
JMenuItem openAllItem = new JMenuItem();
openAllItem.setText("Browse All Notes");
openAllItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK | java.awt.event.InputEvent.ALT_MASK));
openAllItem.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
new BrowseNotes(NoteEditor.this, false).setVisible(true);
}
});
fileMenu.add(openAllItem);
JMenuItem saveAll = new JMenuItem();
saveAll.setText("Save everything");
saveAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
saveAll.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
HashSet<Factoid> facts = _note.getFactoids();
for(Factoid afact : facts) {
try {
afact.getWikiText().saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
try {
afact.saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
HashSet<Attachment> atts = afact.getWikiText().getAttachments();
for(Attachment att : atts) {
try {
att.saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
}
}
try {
_note.saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
try {
_note.getWikiText().saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
for(ObjBase obj : thingsToSave) {
try {
obj.saveDefault();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
fileMenu.add(saveAll);
JMenuItem closeWindow = new JMenuItem();
closeWindow.setText("Close window");
closeWindow.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK));
closeWindow.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
NoteEditor.this.dispose();
}
});
fileMenu.add(closeWindow);
JMenu helpMenu = new JMenu();
helpMenu.setText("Help");
helpMenu.setForeground(Color.WHITE);
menuBar.add(helpMenu);
JMenuItem commandList = new JMenuItem();
commandList.setText("Command help");
commandList.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_H, java.awt.event.InputEvent.CTRL_MASK));
commandList.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
FileObject fo = FileUtil.getConfigFile("org/clothocad/tool/grapevine/commands.csv");
new CommandHelp(fo, "Grapevine Note Editor", "http://wiki.bu.edu/ece-clotho/index.php/Grapevine", "AndersonClothoBugs@gmail.com", "");
}
});
helpMenu.add(commandList);
}
public static void launchListOfNotes(boolean newoption) {
launchAllNotes(newoption);
}
public static void launchPartialList(boolean newoption) {
//Put all the links that exist and are in the user's list; add to chosenuuids
HashMap<String, String> chosenuuids = new HashMap<String, String>();
//Retrieve all links from current user and add to list
ClothoConnection c = Collector.getDefaultConnection();
ClothoQuery mainQuery = c.createQuery( ObjType.NOTE );
ClothoQuery personQuery = mainQuery.createAssociationQuery( Note.Fields.AUTHOR );
personQuery.eq( Person.Fields.DISPLAY_NAME, Collector.getCurrentUser().getDisplayName() );
List<ObjBase> results = mainQuery.getResults();
for(ObjBase obj : results) {
Note anote = (Note) obj;
chosenuuids.put(anote.getUUID(), anote.getName());
System.out.println(anote.getName() + anote.getUUID()+ " was a query hit");
}
//Retrieve all links from "Devices2010" and add to list
mainQuery = c.createQuery( ObjType.NOTE );
personQuery = mainQuery.createAssociationQuery( Note.Fields.AUTHOR );
personQuery.eq( Person.Fields.DISPLAY_NAME, "Devices2010" );
results = mainQuery.getResults();
for(ObjBase obj : results) {
Note anote = (Note) obj;
chosenuuids.put(anote.getUUID(), anote.getName());
System.out.println(anote.getName() + anote.getUUID()+ " was a query hit");
}
//Make a list of ObjLinks
ArrayList<ObjLink> objlinks = new ArrayList<ObjLink>();
objlinks.add(new ObjLink("newnote", ObjType.NOTE, "Create a new note"));
for(String uuid: chosenuuids.keySet()) {
ObjLink ol = new ObjLink(uuid, ObjType.NOTE, chosenuuids.get(uuid));
objlinks.add(ol);
}
//Throw up a chooser
Object[] allNames = objlinks.toArray();
ObjLink link = (ObjLink) JOptionPane.showInputDialog(null, "Choose one", "Note",
JOptionPane.INFORMATION_MESSAGE, null, allNames, allNames[0]);
if(link!=null) {
Note chosen = null;
if(link.uuid.equals("newnote")) {
chosen = new Note("New note", Collector.getCurrentUser(), null);
} else {
chosen = Collector.getNote(link.uuid);
}
if(chosen!=null) {
new NoteEditor(chosen);
}
}
}
/**
* Puts a chooser with all notes written by the current user
* @param newoption
*/
public static void launchAllNotes(boolean newoption) {
//Make a list of Notes
ClothoConnection c = Collector.getDefaultConnection();
ClothoQuery mainQuery = c.createQuery( ObjType.NOTE );
ClothoQuery seqQuery = mainQuery.createAssociationQuery( Note.Fields.AUTHOR );
String name = Collector.getCurrentUser().getDisplayName();
seqQuery.contains( Person.Fields.DISPLAY_NAME, name, false );
List<ObjBase> results = mainQuery.getResults();
//Create a list of links starting with a new note
ArrayList<ObjLink> objlinks = new ArrayList<ObjLink>();
objlinks.add(new ObjLink("newnote", ObjType.NOTE, "Create a new note"));
//Put whatever objLinks were in the collection into the final list
for(ObjBase obj : results) {
objlinks.add(new ObjLink(obj.getUUID(), ObjType.NOTE, obj.getName()));
}
//Throw up a chooser
Object[] allNames = objlinks.toArray();
ObjLink link = (ObjLink) JOptionPane.showInputDialog(null, "Choose one", "Note",
JOptionPane.INFORMATION_MESSAGE, null, allNames, allNames[0]);
if(link!=null) {
Note chosen = null;
if(link.uuid.equals("newnote")) {
chosen = new Note("New note", Collector.getCurrentUser(), null);
} else {
chosen = Collector.getNote(link.uuid);
}
if(chosen!=null) {
new NoteEditor(chosen);
}
}
}
private void putInFactoids() {
new SwingWorker() {
//VARIABLES:
ArrayList<Factoid> listy;
ArrayList<Note> notelisty;
@Override
protected Object doInBackground() throws Exception {
HashSet<Factoid> setty = _note.getFactoids();
wikiListeners.clear();
listy = new ArrayList<Factoid>();
for(Factoid afact : setty) {
listy.add(afact);
ObjBaseObserver wikiListener = new ObjBaseObserver() {
@Override
public void update(ObjBase obj, RefreshEvent evt) {
if(evt.isCondition(RefreshEvent.Condition.WIKITEXT_CHANGED)) {
validate();
}
}
};
afact.getWikiText().isObservedBy(wikiListener);
wikiListeners.add(wikiListener);
}
sortFactoids(listy);
HashSet<Note> notesy = _note.getChildNotes();
notelisty = new ArrayList<Note>();
for(Note anote : notesy) {
notelisty.add(anote);
}
return null;
}
@Override
protected void done() {
CommentScrollPanel.removeAll();
for(final Note currnote: notelisty) {
subNotePanel pl = new subNotePanel(NoteEditor.this, currnote);
CommentScrollPanel.add(pl);
}
for(final Factoid currfact: listy) {
factoidPanel pl = new factoidPanel(NoteEditor.this, currfact);
CommentScrollPanel.add(pl);
}
validate();
}
}.execute();
putLinksToBiologicals();
}
private void putLinksToBiologicals() {
new SwingWorker() {
//VARIABLES:
ArrayList<TransparentButton> listy = new ArrayList<TransparentButton>();
@Override
protected Object doInBackground() throws Exception {
HashSet<String> featLinks = _note.getFeatureLinks();
HashSet<String> famLinks = _note.getFamilyLinks();
HashSet<String> strainLinks = _note.getStrainLinks();
for(String str : featLinks) {
listy.add(createTB(str, ObjType.FEATURE, featureIcon));
}
for(String str : famLinks) {
listy.add(createTB(str, ObjType.FAMILY, familyIcon));
}
for(String str : strainLinks) {
listy.add(createTB(str, ObjType.STRAIN, strainIcon));
}
return null;
}
@Override
protected void done() {
BioLinksBox.removeAll();
for(TransparentButton tb : listy) {
BioLinksBox.add(tb);
}
validate();
repaint();
}
}.execute();
}
private TransparentButton createTB(final String uuid, final ObjType type, ImageIcon icon) {
final linkOutButton tb = new linkOutButton(icon);
tb.setEnterAlpha(0.8f);
tb.setExitAlpha(1.0f);
tb.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
if(tb.isInitiated) {
return;
}
ObjBase obj = Collector.get(type, uuid);
if(obj==null) {
return;
}
thingsToSave.add(obj);
tb.setToolTipText(obj.getName());
new ObjBasePopup(tb, obj);
obj.isDragListenedBy(tb);
tb.isInitiated = true;
}
});
tb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ObjBase obj = Collector.get(type, uuid);
if(obj==null) {
return;
}
thingsToSave.add(obj);
int n = JOptionPane.showConfirmDialog(
NoteEditor.this,
"Are you sure you want to remove this note from " + obj.getName() + "?",
"Confirm unlink",
JOptionPane.YES_NO_OPTION);
if(n==0) {
switch(type) {
case STRAIN:
Strain astrain = (Strain) obj;
astrain.removeNote(_note);
break;
case FAMILY:
Family afam = (Family) obj;
afam.removeNote(_note);
break;
case FEATURE:
Feature feat = (Feature) obj;
feat.removeNote(_note);
break;
default:
break;
}
}
}
});
return tb;
}
private class linkOutButton extends TransparentButton {
public linkOutButton(ImageIcon img) {
super(img);
}
//VARIABLES//
private boolean isInitiated = false;
}
private static void sortFactoids(ArrayList<Factoid> factList) {
Comparator comparator = new Comparator() {
@Override
public int compare ( Object o1, Object o2 ) {
Factoid part1 = (Factoid) o1;
Factoid part2 = (Factoid) o2;
Date i1 = part1.getDateCreated();
Date i2 = part2.getDateCreated();
return i2.compareTo( i1 );
}
};
Collections.sort( factList, comparator );
}
/*-----------------
variables
-----------------*/
Note _note;
private JPanel headerPanel;
private JButton addFactoid;
private JButton addSubNote;
private JButton addFeature;
private JTextField featureTextBox;
private Box BioLinksBox;
private static FileObject _noteList = FileUtil.getConfigFile("org/clothocad/tool/grapevine/existingNotes.txt");
private ScrollablePanel CommentScrollPanel;
private JPanel notesPanel;
private static final ImageIcon factoidIcon = ImageSource.getObjectImage(ObjType.FACTOID, 25);
private static final ImageIcon noteIcon = ImageSource.getObjectImage(ObjType.NOTE, 25);
private static final ImageIcon featureIcon = ImageSource.getObjectImage(ObjType.FEATURE, 20);
private static final ImageIcon strainIcon = ImageSource.getObjectImage(ObjType.STRAIN, 20);
private static final ImageIcon familyIcon = ImageSource.getObjectImage(ObjType.STRAIN, 20);
private ObjBaseObserver noteListener;
private WikiEditorPanel noteWTEd;
private HashSet<ObjBase> thingsToSave = new HashSet<ObjBase>();
private static Color navyblue = new Color(35, 48, 64);
private blueTextField noteTitleField;
private HashSet<ObjBaseObserver> wikiListeners = new HashSet<ObjBaseObserver>();
private static final Border blackline = BorderFactory.createLineBorder(Color.black);
private Font italFont = new Font("Arial", Font.ITALIC, 9);
private Font regFont = new Font("Arial", Font.PLAIN, 11);
}