package org.greenstone.gatherer.feedback; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.tree.*; import javax.swing.event.*; import javax.swing.text.*; import java.io.*; import java.awt.image.*; import java.util.Locale; import java.util.ResourceBundle; import java.text.MessageFormat; import javax.swing.border.*; import java.text.*; import org.greenstone.gatherer.util.JarTools; /** * This is the special class listener. *
This class will record all the action did to any of the
* component inside the window that were open by the application.
*
This listener will start listening since the beginning of the application
* until the user quits from the application. It will record :
*
1. All the information about the window and its components where the action occured.
*
2. All the information about all windows and its components that were open when the action occured.
*
Note : point 1 and 2 only start when user wants to send feedback.
*
3. The action's command the user did.
*
4. The date of when the action occured.
*
The history of the action will be stored in history.log file, which then will be compressed
* to a zip file called MyZipFile.zip.
The listener this class implements are only the listener interface that a javax.swing.* component * could have as stated in API.Some of the listener however is not implemented here as it is considered the event * listened by those listener are not essential to be recorded as they not making any major changes * to the application.
*This listener will only record maximum last 60 instructions user did to the application.
*In this class also we can add some stuff globally through out all the window open by
* the application.
*
This is the class will add a menu called Feedback through out all the window of type JFrame or JDialog
* open by the application.This menu will allow user to either sending feedback or viewing the history
* of all the action user did so far.
* @author Veronica Liesaputra
*/
public class ActionRecorderDialog
implements ActionListener,TreeModelListener,ItemListener,ListDataListener,ChangeListener,
ListSelectionListener,MenuListener,TableColumnModelListener,TreeSelectionListener
{
/**
* This hold the title of the window where the action occured.
*/
private String myframe;
/**
* This hold the title of the window where user called send feedback.
*/
private String feedbackframe;
/**
* This hold the instance of ComponentInformation to get all the information inside a window.
*/
private ComponentInformation compInfo;
/**
* This will hold a record of the action that user just did at the moment.
*/
private History log;
/**
* This will reference to the window where the action occured.
*/
private Window point;
/**
* This hold the vector of all the History instances of all the record of action user did
* so far.
* This vector will hold the history of all the 30 actions user just did.
* There are 2 situation for this vector :
*
1. Before user choose to send feedback.
*
Here, If we want to add another record to the vector when the vector size already 30 then,
* all the 30 records inside the vector will be saved in the temp_history.log file. The vector will
* be cleared and then added with the new record.
*
If the user quits the application, then whats in the vector will be saved to history.log file.
*
2. After user choose to send feedback.
*
When user choose to send feedback,then what happen is what ever inside the vector at the moment
* will be saved to history.log file and then vector will be cleared and it will add the new instruction.
*
If we want to add another record to the vector when the vector size already 30 then,
* all the 30 records inside the vector will be saved in the temp_feedbackhist.log file. The vector will
* be cleared and then added with the new record.
*
If the user finished with the feedback then it will cleared all the vector and load the vector
* inside the history.log to it and add the new record to the vector.
*
If the user quits the application, then whats in the vector will not be saved.
*/
private static Vector vector;
/**
* This is the flag to tell whether or not the image for the window where the action occured is
* finished being added properly to the appropriate record.
* If savefinish = true then it means that the thread of adding image to the record stop, otherwise
* it means its not yet finished so don't stop the thread.
*/
private static boolean savefinish = true;
/**
* This is the thread that contains all the code that the application should be when the user exiting
* the application.
*/
private Thread writeThread;
/**
* This is the thread that contains all the code to add the image of the window where the action
* occured to the proper record.
* This thread will stop if savefinish = true.
*/
private Thread saveThread;
/**
* This is the runtime of this application.
*/
private Runtime run;
/**
* This variable will hold the resource of the words that is stored in feedback.properties file.
* The calling using messages.getString(someString) will caused someString to be translated
* into some other string that is hold in that file.usually it will caused it to be translated
* to the language that the user use or choose to have as stated in Locale.
*/
private static ResourceBundle messages;
/**
* This is an instance of ScreenShot that will allow this application to take screen shot of the whole
* screen or just the screen shot of the window where the actions occured.
*/
private ScreenShot sh;
/**
* This HashMap stored the pair of model and its component.
* This will allow this listener to know which component the model where the actions occured belongs to.
*/
private HashMap modelHash;
/**
* This is the flag variable to sign that the user start the Reporting Feedback sequence.
* If start_rec = false means that the user did not start reporting feedback sequence.
* Otherwise, it means the user start reporting feedback sequence, here there will be changes in the
* content of the vector used to save all the records.This also will change the appearance of the
* window that are currently open by the application. it will make toolbar value = true, rec = true and
* stop_rec = false.
*/
private boolean start_rec = false;
/**
* This is the flag variable to sign that the user are now recording the Reporting Feedback sequence.
* If rec = true, it means its recording, otherwise its false.It also will decide
* the GUI appearance of the window that are currently open by the application.
*/
private boolean rec = false;
/**
* This is the flag variable to sign that user are finished the Reporting Feedback sequence.
* If stop_rec = false, then it means user stop the Reporting Feedback sequence.So here, there will
* be changes in the vector's content. If rec = true then it will also delete the added toolbar on the currently open
* window by the application and its also will delete all the history and file taken when user doing the
* Reporting Feedback sequence.
*/
private boolean stop_rec = true;
/**
* This is the thread do task to take history of the actions.
*/
private Thread saveallThread;
/**
* This is the flag to say whether or not the send feedback button been pushed by user.
*/
private boolean start_fd = false;
/**
* This is a blocker to say that user cannot do anything while we taking history.
*/
private MouseListener mouse_blocker_listener = new MouseAdapter() {};
/**
* This is the feedback interface window.
*/
private FeedbackInterface frame;
/**
* This is an instance of CompListener that will add listener to all the components inside it.
*/
private CompListener compList;
/**
* This is the accelerator key (shortcuts key) for taking screenshot.
*/
private KeyStroke shKey;
/**
* This is the accelerator key (shortcuts key) for reporting feedback.
*/
private KeyStroke fdKey;
/**
* This is the accelerator key (shortcuts key) for viewing history.
*/
private KeyStroke histKey;
/**
* This is the accelerator key (shortcuts key) for sending feedback straight away.
*/
private KeyStroke sndfdKey;
/**
* This is the window that is active at the moment.
*/
private Window activeWindow;
/**
* This is the modal window where user wants to take the screeshot or sending feedback.
*/
private Window modalWindow;
/**
* This constructor will seeting up the data member to its appropriate value.
* It will get the vector that are stored in the history.log file and also it will
* setup the writeThread.
* @param currentLocale is the locale user choose all the text to be displayed as.
*/
public ActionRecorderDialog (Locale currentLocale)
{
messages = ResourceBundle.getBundle("feedback",currentLocale);
setup_UIManager();
fdKey = KeyStroke.getKeyStroke("F2");
histKey = KeyStroke.getKeyStroke("F3");
shKey = KeyStroke.getKeyStroke("F5");
sndfdKey = KeyStroke.getKeyStroke("F12");
/*shKey = KeyStroke.getKeyStroke(KeyEvent.VK_SLASH,InputEvent.CTRL_MASK|
InputEvent.SHIFT_MASK);*/
final ZipFile zip;
zip = new ZipFile();
zip.unZipFile();
vector = getPrev_log("history.log");
sh = new ScreenShot();
modelHash = new HashMap();
compInfo = new ComponentInformation(this,currentLocale,modelHash);
compList = new CompListener(this,modelHash);
EventQueue eq;
eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
eq.push(new MyEventQueue());
run = Runtime.getRuntime();
Runnable writeRun;
writeRun = new Runnable()
{
public void run()
{
try
{
if (stop_rec == true)
{
File f;
f = new File("history.log");
FileOutputStream fos;
fos = new FileOutputStream("history.log");
ObjectOutputStream oos;
oos = new ObjectOutputStream(fos);
oos.writeObject(vector);
vector.removeAllElements();
vector = getPrev_log("temp_history.log");
oos.writeObject(vector);
oos.close();
f = new File("temp_history.log");
f.delete();
}
File f2;
f2 = new File("feedbackhist.log");
f2.delete();
f2 = new File("temp_feedbackhist.log");
f2.delete();
zip.sendZipFile();
writeThread = null;
}
catch (IOException exp) {}
}
};
writeThread = new Thread(writeRun);
run.addShutdownHook(writeThread);
}
/** change the locale for the resource bundle*/
public void setLocale(Locale loc) {
messages = ResourceBundle.getBundle("feedback",loc);
}
/**
* This method will setup some of the GUI appearance that window should have when the user
* choose to start the Reporting Feedback sequence.
*/
public void setup_UIManager ()
{
// why do you do all this???
//UIManager.put("TabbedPane.selected",(new Color(224,240,224)));
//UIManager.put("Button.select",(new Color(224,240,224)));
//UIManager.put("ScrollBar.background",(new Color(176,208,176)));
//UIManager.put("ScrollBar.highlight",(new Color(224,240,224)));
//UIManager.put("ScrollBar.thumb",(new Color(224,240,224)));
//UIManager.put("ScrollBar.track",(new Color(224,240,224)));
//UIManager.put("Tree.textBackground",new Color(224,240,224));
//UIManager.put("Label.font",new Font("Dialog",Font.PLAIN,12));
//UIManager.put("ComboBox.font",new Font("Dialog",Font.PLAIN,12));
//UIManager.put("TextArea.font",new Font("Dialog",Font.PLAIN,12));
}
/**
* This method will get the information about all the components inside the window that are
* open by the application when the action occured and save it to vector.
* @param comp its the component where the user did the action.
* @param command its the action's command the user did.
*/
private void saving (final Component comp,final String command)
{
if ((command.equals(messages.getString("SendFeedback"))) ||
((command.equals("FastSend")) && (stop_rec == false)))
{
start_fd = true;
}
Runnable saveall;
saveall = new Runnable ()
{
public void run ()
{
try
{
Runnable savework;
savework = new Runnable ()
{
public void run ()
{
Date curr_date;
curr_date = new Date();
log = new History(curr_date,command);
if ((start_fd == true)&&(command.equals(messages.getString("WindowOpened"))))
{
start_rec = true;
rec = true;
start_fd = false;
}
getFrame(comp,command);
saveState(command);
saveLog();
if ((point != null) && (rec == true))
{
if (command.equals(messages.getString("WindowClosed")))
{
if (point instanceof JDialog)
if (((JDialog)point).isModal() == true)
if (point == modalWindow)
frame.setComment(false);
}
}
}
};
SwingUtilities.invokeAndWait(savework);
}
catch (Exception ex) {ex.printStackTrace();}
}
};
saveallThread = new Thread(saveall);
saveallThread.start();
}
/**
* This method will get the screen shot of the window where the actions occured and
* add the image also its dimension to the passed record.
* It will caused the saveThread to start so it can allows other stuff to be run concurrently
* and this thread will be stopped when the screen shot of the window alreadyfinished taken.
* @param hst is the record where the image and its dimension should be stored to.
*/
public void saveImage (final History hst)
{
Runnable saveRun;
saveRun = new Runnable()
{
History hist = hst;
public void run()
{
String img,width,height;
Rectangle rect;
int w, h,dimwidth,dimheight;
if (point != null)
{
dimwidth = sh.getWidth();
dimheight = sh.getHeight();
w = point.getWidth();
h = point.getHeight();
try
{
rect = new Rectangle(point.getLocationOnScreen(),
new Dimension(w,h));
if (w >= dimwidth)
w = dimwidth - 50;
width = "" + w;
if (h >= dimheight)
h = dimheight - 50;
height = "" + h;
}
catch (IllegalComponentStateException exp)
{
rect = null;
width = null;
height = null;
}
}
else
{
rect = null;
width = null;
height = null;
}
if (rect != null)
{
img = sh.getImage(rect);
if (savefinish == true)
{
hist.setImage(img,height,width);
}
}
}
};
Thread saveThread;
saveThread = new Thread(saveRun);
saveThread.start();
}
/**
* This method will setup the savefinish value.
* (Precondition: (save != null))
* @param save the value savefinish should have.
*/
public static void setSavefinish (boolean save)
{
savefinish = save;
}
/**
* This method will make the JMenu that is should be added to all the
* window opened by the application.
*
If rec = false then the JMenu will give user option to start the Reporting Feedback sequence
* or Sending feedback or to view the history of actions they have done so far.
*
If rec = true then the JMenu will only give user option to view the history of actions
* they have done so far or sending feedback or taking screenshot.
* @return JMenu that should be added to all window open.
*/
public JMenu makeMenu ()
{
JMenu menu;
JMenuItem item,item2,item3;
ImageIcon icon,icon2,icon3;
icon3 = JarTools.getImage("fastsend.gif");
item3 = new JMenuItem(messages.getString("SendFeedback"),
new ImageIcon(icon3.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item3.setActionCommand("FastSend");
item3.addActionListener(this);
item3.setMnemonic(KeyEvent.VK_N);
item3.setAccelerator(sndfdKey);
item3.setToolTipText("Send feedback now");
item = null;
if (rec == false)
{
icon = JarTools.getImage("feedback.gif");
item = new JMenuItem("Report Feedback",
new ImageIcon(icon.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand(messages.getString("SendFeedback"));
item.addActionListener(this);
item.setMnemonic(KeyEvent.VK_F);
item.setAccelerator(fdKey);
item.setToolTipText("Report feedback");
}
else
{
icon = JarTools.getImage("camera.gif");
item = new JMenuItem(messages.getString("ScreenShot"),
new ImageIcon(icon.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand("ScreenShot");
item.setMnemonic(KeyEvent.VK_S);
item.addActionListener(this);
item.setAccelerator(shKey);
item.setToolTipText("Take screenshot of the whole screen.");
}
icon2 = JarTools.getImage("history.gif");
item2 = new JMenuItem(messages.getString("LookHistory"),
new ImageIcon(icon2.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item2.setActionCommand(messages.getString("LookHistory"));
item2.addActionListener(this);
item2.setMnemonic(KeyEvent.VK_H);
item2.setAccelerator(histKey);
item2.setToolTipText(messages.getString("LookHistoryButton"));
menu = new JMenu (messages.getString("Feedback"));
menu.setMnemonic(KeyEvent.VK_D);
if (item != null)
menu.add(item);
menu.add(item3);
menu.add(item2);
if (rec == true)
menu.setBackground(new Color(176,209,217));
else
menu.setBackground(new Color(204,204,204));
return menu;
}
public void refreshLocationAndSize(Window window) {
window.setLocation(window.getX(),window.getY());
Toolkit kit;
kit = Toolkit.getDefaultToolkit();
Dimension screenSize;
screenSize = kit.getScreenSize();
int screenHeight;
screenHeight = screenSize.height;
int screenWidth;
screenWidth = screenSize.width;
if ((window.getSize().width > screenWidth) &&
(window.getSize().height > screenHeight)) {
window.setSize(window.getPreferredSize());
}
}
/**
* This method will setup the GUI that this window should have at the moment.
* If start_rec is true then JMenu don't have the option to start Reporting Feedback sequence in it.
* If stop_rec is true and rec is true then JMenu there should be an option to start Reporting Feedback sequence in it.
* The JMenu will only be affected window of type JDialog and JFrame only.
* (Precondition: (window != null))
* @param window its the window that we want to set the GUI
*/
public void setUI (Window window)
{
if (start_rec == true) {
if (window instanceof JFrame) {
JFrame a;
a = (JFrame) window;
JMenuBar menuBar;
menuBar = a.getJMenuBar();
if (menuBar != null) {
JMenu temp_menu;
temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
temp_menu.setBackground(new Color(176,209,217));
temp_menu.remove(0);
JMenuItem item;
ImageIcon icon;
icon = JarTools.getImage("camera.gif");
item = new JMenuItem(messages.getString("ScreenShot"),
new ImageIcon(icon.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand("ScreenShot");
item.setMnemonic(KeyEvent.VK_S);
item.addActionListener(this);
item.setAccelerator(shKey);
item.setToolTipText("Take screenshot of this window");
temp_menu.insert(item,0);
}
refreshLocationAndSize(a);
a.validate();
a.repaint();
}
else if (window instanceof JDialog) {
JDialog a;
a = (JDialog) window;
JMenuBar menuBar;
menuBar = a.getJMenuBar();
if (menuBar != null) {
JMenu temp_menu;
temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
temp_menu.setBackground(new Color(176,209,217));
temp_menu.remove(0);
JMenuItem item;
ImageIcon icon;
icon = JarTools.getImage("camera.gif");
item = new JMenuItem(messages.getString("ScreenShot"),
new ImageIcon(icon.getImage().getScaledInstance
(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand("ScreenShot");
item.setMnemonic(KeyEvent.VK_S);
item.addActionListener(this);
item.setAccelerator(shKey);
item.setToolTipText("Take screenshot of this window");
temp_menu.insert(item,0);
}
refreshLocationAndSize(a);
a.validate();
a.repaint();
}
else if (window instanceof JWindow) {
JWindow a;
a = (JWindow) window;
((JComponent) a.getContentPane()).unregisterKeyboardAction(fdKey);
((JComponent) a.getContentPane()).registerKeyboardAction(this, "ScreenShot", shKey,JComponent.WHEN_IN_FOCUSED_WINDOW);
}
else
return;
}
else {
if ((stop_rec == true) && (rec == true)) {
if (window instanceof JFrame) {
JFrame a;
a = (JFrame) window;
JMenuBar menuBar;
menuBar = a.getJMenuBar();
if (menuBar != null) {
JMenu temp_menu;
temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
temp_menu.setBackground(new Color(204,204,204));
temp_menu.remove(0);
ImageIcon icon;
JMenuItem item;
icon = JarTools.getImage("feedback.gif");
item = new JMenuItem("Report Feedback", new ImageIcon(icon.getImage().getScaledInstance(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand(messages.getString("SendFeedback"));
item.addActionListener(this);
item.setMnemonic(KeyEvent.VK_F);
item.setAccelerator(fdKey);
item.setToolTipText(messages.getString("SendFeedbackButton"));
temp_menu.insert(item,0);
}
a.setSize(a.getPreferredSize());
a.validate();
a.repaint();
}
else if (window instanceof JDialog) {
JDialog a;
a = (JDialog) window;
JMenuBar menuBar;
menuBar = a.getJMenuBar();
if (menuBar != null) {
JMenu temp_menu;
temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
temp_menu.setBackground(new Color(204,204,204));
temp_menu.remove(0);
ImageIcon icon;
JMenuItem item;
icon = JarTools.getImage("feedback.gif");
item = new JMenuItem("Report Feedback", new ImageIcon(icon.getImage().getScaledInstance(20,20,Image.SCALE_SMOOTH)));
item.setActionCommand(messages.getString("SendFeedback"));
item.addActionListener(this);
item.setMnemonic(KeyEvent.VK_F);
item.setAccelerator(fdKey);
item.setToolTipText(messages.getString("SendFeedbackButton"));
temp_menu.insert(item,0);
}
a.setSize(a.getPreferredSize());
a.validate();
a.repaint();
}
else if (window instanceof JWindow) {
JWindow a;
a = (JWindow) window;
((JComponent) a.getContentPane()).registerKeyboardAction(this, messages.getString("SendFeedback"), fdKey, JComponent.WHEN_IN_FOCUSED_WINDOW);
((JComponent) a.getContentPane()).unregisterKeyboardAction(shKey);
}
else
return;
}
else
return;
}
}
/**
* This will make an Window[] convert to ArrayList that contain list of Window.
* (Precondition: (windows != null))
* @param windows the array that we want to convert to ArrayList
* @return the array list that contains all object in array windows.
*/
public ArrayList addToArrayList (Window[] windows,ArrayList arr)
{
int i;
for (i = 0 ; i < windows.length ; i++)
{
arr.add(windows[i]);
}
return arr;
}
/**
* This method will get all the information of the window that are currently open when the action
* occured and these windows are not the window where the action occured.
* It will add these windows information to the current record and it will also setting up the
* GUI for each of these windows.
* @param command the action's command user did.
*/
public void saveState(String command)
{
Window[] frame_windows;
ArrayList windows;
Frame[] frames;
int i,j;
if (log == null)
return;
windows = new ArrayList();
frames = Frame.getFrames();
for (i = 0 ; i