package com.link_intersystems.gitdirstat.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JRootPane;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;
import org.apache.commons.io.IOUtils;
import com.link_intersystems.gitdirstat.domain.GitRepositoryAccess;
import com.link_intersystems.gitdirstat.domain.TreeObject;
import com.link_intersystems.gitdirstat.ui.UIContext.IconType;
import com.link_intersystems.gitdirstat.ui.help.OpenAboutAction;
import com.link_intersystems.swing.ListModelSelectionMediator;
import com.link_intersystems.swing.ProgressDialogMonitor;
import com.link_intersystems.swing.ProgressMonitor;
import com.link_intersystems.swing.SingleActionSelectionMediator;
public class MainFrame implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3532566379033471650L;
public static final String MB_PATH_FILE = "file";
public static final String MB_PATH_VIEW = "view";
public static final String MB_PATH_HELP = "help";
private static class ButtonGroupActionSelectionSync implements
PropertyChangeListener {
private ButtonGroup buttonGroup;
public ButtonGroupActionSelectionSync(ButtonGroup buttonGroup) {
this.buttonGroup = buttonGroup;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
Action selectedAction = (Action) evt.getNewValue();
Enumeration<AbstractButton> elements = buttonGroup.getElements();
while (elements.hasMoreElements()) {
AbstractButton abstractButton = elements.nextElement();
Action action = abstractButton.getAction();
buttonGroup.setSelected(abstractButton.getModel(),
selectedAction.equals(action));
}
}
};
private class UIContextImpl implements UIContext {
private MainFrame mainFrame;
public UIContextImpl(MainFrame mainFrame) {
this.mainFrame = mainFrame;
}
@Override
public Window getMainFrame() {
return mainFrame.mainFrame;
}
@Override
public ImageIcon getIcon(IconType iconType) {
String iconFromClasspath = getIconFromClasspath(iconType.getName());
return getIcon(iconFromClasspath);
}
public ImageIcon getIcon(String classpath) {
InputStream resourceAsStream = getClass().getClassLoader()
.getResourceAsStream(classpath);
try {
byte[] imageData = IOUtils.toByteArray(resourceAsStream);
ImageIcon imageIcon = new ImageIcon(imageData);
return imageIcon;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String getIconFromClasspath(String iconName) {
String resolution = "16x16";
return MessageFormat.format("icons/{0}/{1}", resolution, iconName);
}
@Override
public ProgressMonitor getProgressMonitor() {
return MainFrame.this.progressDialogMonitor;
}
}
private Map<String, SingleActionSelectionMediator> actionGroupMediator = new HashMap<String, SingleActionSelectionMediator>();
private UIContextImpl uiContext = new UIContextImpl(this);
private JFrame mainFrame = new JFrame("GitDirStat");
private JToolBar jToolBar = new JToolBar();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu("File");
private JMenu viewMenu = new JMenu("View");
private JMenu helpMenu = new JMenu("Help");
private JPanel actionPanel = new JPanel();
private Component mainComponent;
private ProgressDialogMonitor progressDialogMonitor = new ProgressDialogMonitor(
mainFrame);
private OpenRepositoryAction openRepositoryAction;
private OpenAction openRepoAction;
private Action startupAction;
private GitRepositoryModel repoModel;
private ListModelSelectionMediator<TreeObject> listSelectionMediator;
public MainFrame(GitDirStatUIArguments arguments,
GitRepositoryAccess repoAccess) {
repoModel = new GitRepositoryModel();
File gitRepositoryDir = arguments.getGitRepositoryDir();
if (gitRepositoryDir != null) {
repoModel.setGitDir(gitRepositoryDir);
startupAction = new OpenRepositoryAction(uiContext, repoModel,
repoAccess);
}
configureMainFrame();
progressDialogMonitor.setMillisToDecideToPopup(100);
progressDialogMonitor.setETAEnabled(true);
GitRepositoryView gitRepositoryView = new GitRepositoryView();
gitRepositoryView.setModel(repoModel);
setMainComponent(gitRepositoryView);
openRepositoryAction = new OpenRepositoryAction(uiContext, repoModel,
repoAccess);
openRepositoryAction.setDisableWhileRunning(true);
openRepoAction = new OpenAction(repoModel, repoAccess, uiContext);
addMenuBarAction(MB_PATH_FILE, openRepoAction);
addMenuBarAction(MB_PATH_FILE, openRepositoryAction);
OpenAboutAction openAboutAction = new OpenAboutAction(uiContext);
openAboutAction.putValue(Action.NAME, "About");
addMenuBarAction(MB_PATH_HELP, openAboutAction);
Action showTableAction = gitRepositoryView.getSetTableAction();
showTableAction.putValue(Action.NAME, "Show table");
Action showTreeAction = gitRepositoryView.getSetTreeAction();
showTreeAction.putValue(Action.NAME, "Show tree");
addMenuBarActionGroup(MB_PATH_VIEW, showTableAction, showTreeAction);
addToolbarActions(repoAccess);
}
private void addToolbarActions(GitRepositoryAccess repoAccess) {
addUpdateRepositoryAction();
addRemovePathAction(repoAccess);
}
private void addUpdateRepositoryAction() {
openRepositoryAction.putValue(Action.NAME, "Update");
openRepositoryAction.putValue(Action.SHORT_DESCRIPTION,
"Update repository");
openRepositoryAction.addDisabledActionWhileRunning(openRepoAction);
addToolbarAction(openRepositoryAction);
}
private void addRemovePathAction(GitRepositoryAccess repoAccess) {
RemovePathAction removePathAction = new RemovePathAction(repoModel,
repoAccess, uiContext);
removePathAction.putValue(Action.SMALL_ICON,
uiContext.getIcon(IconType.CLEAN));
removePathAction.setProgressMonitor(progressDialogMonitor);
removePathAction.putValue(Action.NAME, "Remove selected paths");
removePathAction.putValue(Action.SHORT_DESCRIPTION,
"Remove selected paths from repository");
addToolbarAction(removePathAction);
PathModel pathListModel = repoModel.getPathModel();
listSelectionMediator = new ListModelSelectionMediator<TreeObject>();
listSelectionMediator.setSelectionModel(pathListModel
.getSelectionModel());
listSelectionMediator
.addDisabledActionOnEmptySelection(removePathAction);
}
private void configureMainFrame() {
Dimension size = getInitialSize();
mainFrame.setSize(size);
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setLocationRelativeTo(null);
ImageIcon gitIcon = uiContext.getIcon("icons/Git-Icon-1788C.png");
mainFrame.setIconImage(gitIcon.getImage());
JRootPane rootPane = mainFrame.getRootPane();
rootPane.setJMenuBar(menuBar);
menuBar.add(fileMenu);
menuBar.add(viewMenu);
menuBar.add(helpMenu);
actionPanel.setLayout(new BorderLayout());
actionPanel.add(jToolBar, BorderLayout.CENTER);
mainFrame.add(actionPanel, BorderLayout.NORTH);
}
private Dimension getInitialSize() {
GraphicsEnvironment lge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreenDevice = lge.getDefaultScreenDevice();
GraphicsConfiguration defaultConfiguration = defaultScreenDevice
.getDefaultConfiguration();
Rectangle bounds = defaultConfiguration.getBounds();
int initialWidth = (int) (bounds.width * 0.8);
int initialHeight = (int) (bounds.height * 0.8);
return new Dimension(initialWidth, initialHeight);
}
public void addToolbarAction(Action action) {
this.jToolBar.add(action);
}
public void addMenuBarAction(String menubarPath, Action action) {
JMenuItem actionItem = new JMenuItem(action);
JMenu menu = getMenu(menubarPath);
menu.add(actionItem);
}
public void setMainComponent(JComponent component) {
Container contentPane = mainFrame.getContentPane();
if (mainComponent != null) {
contentPane.remove(mainComponent);
}
contentPane.add(component, BorderLayout.CENTER);
mainComponent = component;
contentPane.invalidate();
contentPane.validate();
contentPane.repaint();
}
public void setVisible(boolean visible) {
mainFrame.setVisible(visible);
if (startupAction != null) {
startupAction.actionPerformed(null);
}
}
public void addMenuBarActionGroup(String menubarPath, Action... actions) {
JMenu menu = getMenu(menubarPath);
final ButtonGroup group = new ButtonGroup();
SingleActionSelectionMediator actionGroupMediator = getActionGroupMediator(menubarPath);
actionGroupMediator.setActionGroup(actions);
ButtonGroupActionSelectionSync buttonGroupActionSelectionSync = new ButtonGroupActionSelectionSync(
group);
actionGroupMediator.addPropertyChangeListener(
SingleActionSelectionMediator.PROP_SELECTED_ACTION,
buttonGroupActionSelectionSync);
JRadioButtonMenuItem radioButton = null;
for (int i = 0; i < actions.length; i++) {
Action action = actions[i];
radioButton = new JRadioButtonMenuItem(action);
group.add(radioButton);
menu.add(radioButton);
Boolean selected = (Boolean) action.getValue(Action.SELECTED_KEY);
boolean isSelected = selected != null && selected;
group.setSelected(radioButton.getModel(), isSelected);
}
}
private JMenu getMenu(String menubarPath) {
JMenu menu = null;
if (menubarPath.startsWith(MB_PATH_FILE)) {
menu = fileMenu;
} else if (menubarPath.startsWith(MB_PATH_VIEW)) {
menu = viewMenu;
} else if (menubarPath.startsWith(MB_PATH_HELP)) {
menu = helpMenu;
} else {
throw new IllegalArgumentException("Menubar path " + menubarPath
+ " is not supported");
}
return menu;
}
private SingleActionSelectionMediator getActionGroupMediator(
String menubarPath) {
SingleActionSelectionMediator selectionMediator = actionGroupMediator
.get(menubarPath);
if (selectionMediator == null) {
selectionMediator = new SingleActionSelectionMediator();
actionGroupMediator.put(menubarPath, selectionMediator);
}
return selectionMediator;
}
public Action createMainComponentSetterAction(String actionName,
JComponent component) {
class MainComponentSetterAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 3614889449548477302L;
private JComponent component;
public MainComponentSetterAction(String name, JComponent component) {
super(name);
this.component = component;
}
@Override
public void actionPerformed(ActionEvent e) {
setMainComponent(component);
}
}
return new MainComponentSetterAction(actionName, component);
}
public JFrame getMainFrame() {
return mainFrame;
}
}