package org.chartsy.main;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.Serializable;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import org.chartsy.main.data.DataProvider;
import org.chartsy.main.data.Stock;
import org.chartsy.main.exceptions.InvalidStockException;
import org.chartsy.main.exceptions.RegistrationException;
import org.chartsy.main.exceptions.StockNotFoundException;
import org.chartsy.main.history.HistoryItem;
import org.chartsy.main.managers.DataProviderManager;
import org.chartsy.main.resources.ResourcesUtils;
import org.chartsy.main.utils.SerialVersion;
import org.chartsy.main.utils.UppercaseDocumentFilter;
import org.chartsy.main.utils.autocomplete.StockAutoCompleter;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.Cancellable;
import org.openide.util.RequestProcessor;
import org.openide.util.Task;
import org.openide.util.TaskListener;
/**
*
* @author viorel.gheba
*/
public class SymbolChanger extends JToolBar implements Serializable
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
private final static RequestProcessor RP = new RequestProcessor("interruptible tasks", 1, true);
private ChartFrame chartFrame;
private JTextField txtSymbol;
private JButton btnSubmit;
private JButton btnBack;
private JButton btnForward;
private JButton btnBackHistory;
private JButton btnForwardHistory;
private String dataProvider;
private boolean canOpen = true;
public SymbolChanger(ChartFrame frame)
{
super(JToolBar.HORIZONTAL);
chartFrame = frame;
setFloatable(false);
setOpaque(false);
setDoubleBuffered(true);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
initComponents();
}
private void initComponents()
{
Insets margins = new Insets(0, 2, 0, 2);
// symbol text field
txtSymbol = new JTextField(6);
((AbstractDocument) txtSymbol.getDocument()).setDocumentFilter(new UppercaseDocumentFilter());
txtSymbol.setMargin(margins);
txtSymbol.setText(chartFrame.getChartData().getStock().getKey());
Dimension d = new Dimension(50, 20);
txtSymbol.setPreferredSize(d);
txtSymbol.setMinimumSize(d);
txtSymbol.setMaximumSize(d);
// submit button
btnSubmit = new JButton(new ChangeStock());
btnSubmit.setText("");
// back button
btnBack = new JButton(new BackAction());
btnBack.setText("");
// forward button
btnForward = new JButton(new ForwardAction());
btnForward.setText("");
// back history button
btnBackHistory = new JButton(new BackListAction());
btnBackHistory.setText("");
// forward history button
btnForwardHistory = new JButton(new ForwardListAction());
btnForwardHistory.setText("");
if (!chartFrame.getHistory().hasBackHistory())
{
btnBack.setEnabled(false);
btnBackHistory.setEnabled(false);
}
if (!chartFrame.getHistory().hasFwdHistory())
{
btnForward.setEnabled(false);
btnForwardHistory.setEnabled(false);
}
add(txtSymbol);
add(btnSubmit);
add(btnBack);
add(btnForward);
add(btnBackHistory);
add(btnForwardHistory);
dataProvider = chartFrame.getChartData().getDataProviderName();
final StockAutoCompleter completer = new StockAutoCompleter(txtSymbol);
completer.setDataProvider(dataProvider);
}
public Action submit = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
btnSubmit.doClick();
}
};
public void updateToolbar()
{
removeAll();
initComponents();
validate();
repaint();
}
private void buttonsStatus(boolean status)
{
btnBack.setEnabled(status);
btnBackHistory.setEnabled(status);
btnForward.setEnabled(status);
btnForwardHistory.setEnabled(status);
btnSubmit.setEnabled(status);
}
private void notifyError(Throwable t)
{
canOpen = false;
NotifyDescriptor descriptor = new NotifyDescriptor.Message(t.getMessage(), NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(descriptor);
}
private static abstract class SymbolChangerAction extends AbstractAction
{
public SymbolChangerAction(String name, String tooltip, String icon)
{
putValue(NAME, name);
putValue(SHORT_DESCRIPTION, tooltip);
if (icon != null)
{
putValue(SMALL_ICON, ResourcesUtils.getIcon(icon));
putValue(LARGE_ICON_KEY, ResourcesUtils.getIcon(icon));
}
}
}
public class ChangeStock extends SymbolChangerAction
{
private RequestProcessor.Task stockTask;
public ChangeStock()
{
super("Submit", "Submit Symbol", "ok");
}
@Override
public void actionPerformed(ActionEvent e)
{
buttonsStatus(false);
final String symbol = txtSymbol.getText().trim();
final DataProvider provider = DataProviderManager.getDefault().getDataProvider(dataProvider);
final ProgressHandle handle = ProgressHandleFactory.createHandle("Aquiring stock info", new Cancellable()
{
@Override
public boolean cancel()
{
canOpen = false;
if (stockTask != null)
{
return stockTask.cancel();
}
return true;
}
});
final Runnable runnable = new Runnable()
{
@Override
public void run()
{
handle.start();
handle.switchToIndeterminate();
canOpen = true;
try
{
if (!provider.stockExists(symbol))
provider.fetchStock(symbol);
} catch (InvalidStockException ex)
{
handle.finish();
notifyError(ex);
} catch (StockNotFoundException ex)
{
handle.finish();
notifyError(ex);
} catch (RegistrationException ex)
{
handle.finish();
notifyError(ex);
} catch (IOException ex)
{
handle.finish();
notifyError(new InvalidStockException());
}
}
};
stockTask = RP.create(runnable);
stockTask.addTaskListener(new TaskListener()
{
@Override
public void taskFinished(Task task)
{
handle.finish();
if (canOpen)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
buttonsStatus(true);
HistoryItem current = chartFrame.getHistory().getCurrent();
chartFrame.getHistory().clearForwardHistory();
chartFrame.getHistory().addHistoryItem(current);
Stock stock = provider.fetchStockFromCache(symbol);
chartFrame.stockChanged(stock);
}
});
}
}
});
stockTask.schedule(0);
}
}
public class BackAction extends SymbolChangerAction
{
public BackAction()
{
super("Go Back", "Go Back", "back");
}
@Override
public void actionPerformed(ActionEvent e)
{
buttonsStatus(false);
HistoryItem item = chartFrame.getHistory().go(-1);
if (item != null)
{
chartFrame.historyItemChanged(item);
}
buttonsStatus(true);
}
}
public class ForwardAction extends SymbolChangerAction
{
public ForwardAction()
{
super("Go Forward", "Go Forward", "forward");
}
@Override
public void actionPerformed(ActionEvent e)
{
buttonsStatus(false);
HistoryItem item = chartFrame.getHistory().go(1);
if (item != null)
{
chartFrame.historyItemChanged(item);
}
buttonsStatus(true);
updateToolbar();
}
}
public class BackListAction extends SymbolChangerAction
{
public BackListAction()
{
super("Go Back", "Go Back", "backHistory");
}
@Override
public void actionPerformed(ActionEvent e)
{
HistoryItem[] items = chartFrame.getHistory().getBackHistoryList();
if (items.length > 0)
{
JButton btn = (JButton) e.getSource();
JPopupMenu popup = new JPopupMenu();
JMenuItem item;
for (int i = items.length - 1; i >= 0; i--)
{
final int index = i - items.length;
if (items[i] != null)
{
String name =
items[i].getStock().getKey()
+ " : "
+ items[i].getInterval();
popup.add(item = new JMenuItem(new GoToItemAction(name, index)));
item.setMargin(new Insets(0, 0, 0, 0));
}
}
popup.addSeparator();
popup.add(item = new JMenuItem(new ClearHistoryAction(true)));
item.setMargin(new Insets(0, 0, 0, 0));
popup.show(btn, 0, btn.getHeight());
}
}
}
public class ForwardListAction extends SymbolChangerAction
{
public ForwardListAction()
{
super("Go Forward", "Go Forward", "forwardHistory");
}
@Override
public void actionPerformed(ActionEvent e)
{
HistoryItem[] items = chartFrame.getHistory().getFwdHistoryList();
if (items.length > 0)
{
JButton btn = (JButton) e.getSource();
JPopupMenu popup = new JPopupMenu();
JMenuItem item;
for (int i = items.length - 1; i >= 0; i--)
{
final int index = Math.abs(i - items.length);
if (items[i] != null)
{
String name =
items[i].getStock().getKey()
+ " : "
+ items[i].getInterval();
popup.add(item = new JMenuItem(new GoToItemAction(name, index)));
item.setMargin(new Insets(0, 0, 0, 0));
}
}
popup.addSeparator();
popup.add(item = new JMenuItem(new ClearHistoryAction(false)));
item.setMargin(new Insets(0, 0, 0, 0));
popup.show(btn, 0, btn.getHeight());
}
}
}
public class GoToItemAction extends SymbolChangerAction
{
private int step = 0;
public GoToItemAction(String name, int step)
{
super(name, name, null);
this.step = step;
}
@Override
public void actionPerformed(ActionEvent e)
{
buttonsStatus(false);
HistoryItem item = chartFrame.getHistory().go(step);
if (item != null)
{
chartFrame.historyItemChanged(item);
}
buttonsStatus(true);
}
}
public class ClearHistoryAction extends SymbolChangerAction
{
private boolean back;
public ClearHistoryAction(boolean back)
{
super("Clear", "Clear", null);
this.back = back;
}
@Override
public void actionPerformed(ActionEvent e)
{
buttonsStatus(false);
if (back)
{
chartFrame.getHistory().clearBackHistory();
} else
{
chartFrame.getHistory().clearForwardHistory();
}
buttonsStatus(true);
updateToolbar();
}
}
}