Skip to content

Commit

Permalink
Add duplicate button to tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor Cher committed Aug 26, 2013
1 parent 706d7fb commit c283f2f
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 66 deletions.
28 changes: 28 additions & 0 deletions src/main/java/hrider/ui/Images.java
@@ -0,0 +1,28 @@
package hrider.ui;

import javax.swing.*;
import java.util.HashMap;
import java.util.Map;

public class Images {

private static Map<String, ImageIcon> images;

private Images() {
}

static {
images = new HashMap<String, ImageIcon>();
}

public static ImageIcon get(String name) {
if (images.containsKey(name)) {
return images.get(name);
}

ImageIcon icon = new ImageIcon(Thread.currentThread().getContextClassLoader().getResource(String.format("images/%s.png", name)));
images.put(name, icon);

return icon;
}
}
Expand Up @@ -21,14 +21,21 @@
* @author Igor Cher
* @version %I%, %G%
* <p/>
* This is a listener interface that allows to register for tab closed events.
* This is a listener interface that allows to register for tab action events.
*/
public interface TabClosedListener {
public interface TabActionListener {

/**
* The method is called each time the tab of {@link JTabbedPane} is closed by the user.
*
* @param component The component of the closed tab.
*/
void onTabClosed(Component component);

/**
* The method is called each time the tab of {@link JTabbedPane} is being duplicated by the user.
*
* @param component The component of the duplicated tab.
*/
void onTabDuplicated(Component component);
}
@@ -1,6 +1,7 @@
package hrider.ui.controls;

import hrider.ui.TabClosedListener;
import hrider.ui.Images;
import hrider.ui.TabActionListener;

import javax.swing.*;
import java.awt.*;
Expand Down Expand Up @@ -29,60 +30,78 @@
* <p/>
* This class represents a custom button used on tabs in tab component. The button allows to user to close unnecessary tabs.
*/
public class JCloseButton extends JPanel {
public class JTab extends JPanel {

//region Constants
private static final long serialVersionUID = 3457653319908745576L;
//endregion

//region Variables
private List<TabClosedListener> listeners;
private List<TabActionListener> listeners;
//endregion

//region Constructor
public JCloseButton(final String title, final JTabbedPane pane) {
public JTab(final String title, final JTabbedPane pane) {

this.listeners = new ArrayList<TabClosedListener>();
setOpaque(false);

this.listeners = new ArrayList<TabActionListener>();

JLabel label = new JLabel();
label.setText(title);
label.setHorizontalTextPosition(SwingConstants.TRAILING);
label.setIcon(new ImageIcon(Thread.currentThread().getContextClassLoader().getResource("images/server.png")));

JButton button = new JButton();
label.setIcon(Images.get("server"));

setOpaque(false);
JButton closeButton = new JButton(Images.get("close"));
closeButton.setPreferredSize(new Dimension(16, 16));
closeButton.setToolTipText("Close the tab");
closeButton.setFocusPainted(false);
closeButton.setOpaque(false);
closeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

button.setPreferredSize(new Dimension(16, 16));
button.addActionListener(
closeButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (pane.getTabCount() > 1) {
pane.removeTabAt(pane.indexOfTab(title));

for (TabClosedListener listener : JCloseButton.this.listeners) {
listener.onTabClosed(JCloseButton.this);
for (TabActionListener listener : JTab.this.listeners) {
listener.onTabClosed(JTab.this);
}
}
}
});

button.setIcon(new ImageIcon(Thread.currentThread().getContextClassLoader().getResource("images/close.png")));
button.setFocusPainted(false);
button.setOpaque(false);
JButton duplicateButton = new JButton(Images.get("duplicate"));
duplicateButton.setPreferredSize(new Dimension(16, 16));
duplicateButton.setToolTipText("Duplicate the tab");
duplicateButton.setFocusPainted(false);
duplicateButton.setOpaque(false);
duplicateButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

duplicateButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (TabActionListener listener : JTab.this.listeners) {
listener.onTabDuplicated(JTab.this);
}
}
});

add(label);
add(button);
add(closeButton);
add(duplicateButton);
}
//endregion

//region Public Methods
public void addTabClosedListener(TabClosedListener listener) {
public void addTabActionListener(TabActionListener listener) {
this.listeners.add(listener);
}

public void removeTabClosedListener(TabClosedListener listener) {
public void removeTabActionListener(TabActionListener listener) {
this.listeners.remove(listener);
}
//endregion
Expand Down
90 changes: 59 additions & 31 deletions src/main/java/hrider/ui/forms/Window.java
Expand Up @@ -19,12 +19,9 @@
import hrider.system.ClipboardData;
import hrider.system.InMemoryClipboard;
import hrider.system.Version;
import hrider.ui.MessageHandler;
import hrider.ui.MessageHandlerListener;
import hrider.ui.TabClosedListener;
import hrider.ui.UIAction;
import hrider.ui.controls.JCloseButton;
import hrider.ui.*;
import hrider.ui.controls.JLinkButton;
import hrider.ui.controls.JTab;
import hrider.ui.views.DesignerView;

import javax.swing.*;
Expand All @@ -35,6 +32,7 @@
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.jar.Manifest;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -64,27 +62,29 @@ public class Window {
//endregion

//region Variables
private JPanel topPanel;
private JTabbedPane tabbedPane;
private JLinkButton connectToCluster;
private JPanel actionPanel;
private JLabel actionLabel1;
private JLinkButton actionLabel2;
private JLabel actionLabel3;
private JButton copyToClipboard;
private JLinkButton newVersionAvailable;
private boolean canceled;
private UIAction uiAction;
private String lastError;
private Map<Component, DesignerView> viewMap;
private Properties updateInfo;
private JFrame frame;
private JPanel topPanel;
private JTabbedPane tabbedPane;
private JLinkButton connectToCluster;
private JPanel actionPanel;
private JLabel actionLabel1;
private JLinkButton actionLabel2;
private JLabel actionLabel3;
private JButton copyToClipboard;
private JLinkButton newVersionAvailable;
private boolean canceled;
private UIAction uiAction;
private String lastError;
private Map<Component, DesignerView> viewMap;
private Map<String, List<DesignerView>> viewList;
private Properties updateInfo;
private JFrame frame;
//endregion

//region Constructor
public Window() {
this.updateInfo = new Properties();
this.viewMap = new HashMap<Component, DesignerView>();
this.viewList = new HashMap<String, List<DesignerView>>();

Font font = this.actionLabel1.getFont();
this.actionLabel1.setFont(font.deriveFont(font.getStyle() | ~Font.BOLD));
Expand Down Expand Up @@ -280,7 +280,7 @@ private static void createAndShowGUI() {
frame.setContentPane(window.topPanel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setIconImage(new ImageIcon(Thread.currentThread().getContextClassLoader().getResource("images/h-rider.png")).getImage());
frame.setIconImage(Images.get("h-rider").getImage());

// Display the window.
frame.pack();
Expand Down Expand Up @@ -440,20 +440,31 @@ public void run() {
*
* @param connection A connection to be used to connect to the cluster.
*/
private void loadView(Connection connection) {
DesignerView view = new DesignerView(this.topPanel, connection);
private DesignerView loadView(final Connection connection) {
final DesignerView view = new DesignerView(this.topPanel, connection);

int index = this.tabbedPane.getTabCount();

JCloseButton closeButton = new JCloseButton(connection.getServerName(), this.tabbedPane);
this.viewMap.put(closeButton, view);
JTab tab = new JTab(connection.getServerName(), this.tabbedPane);
this.viewMap.put(tab, view);

closeButton.addTabClosedListener(
new TabClosedListener() {
List<DesignerView> views = this.viewList.get(connection.getServerName());
if (views == null) {
views = new ArrayList<DesignerView>();
this.viewList.put(connection.getServerName(), views);
}

views.add(view);

tab.addTabActionListener(
new TabActionListener() {
@Override
public void onTabClosed(Component component) {
DesignerView designerView = viewMap.get(component);

List<DesignerView> list = viewList.get(designerView.getConnection().getServerName());
list.remove(designerView);

ClipboardData<DataTable> data = InMemoryClipboard.getData();
if (data != null) {
Connection helper = data.getData().getConnection();
Expand All @@ -464,22 +475,39 @@ public void onTabClosed(Component component) {
}
}

ViewConfig.instance().removeCluster(designerView.getConnection().getServerName());
if (list.isEmpty()) {
ViewConfig.instance().removeCluster(designerView.getConnection().getServerName());
PropertiesConfig.fileRemove(designerView.getConnection().getServerName());

PropertiesConfig.fileRemove(designerView.getConnection().getServerName());
viewList.remove(designerView.getConnection().getServerName());
}

ConnectionManager.release(designerView.getConnection().getConnectionDetails());
viewMap.remove(component);
}

@Override
public void onTabDuplicated(Component component) {
try {
DesignerView duplicatedView = loadView(new Connection(connection.getConnectionDetails()));
duplicatedView.setSelectedTableName(view.getSelectedTableName());
}
catch (IOException ex) {
MessageHandler.addError(String.format("Failed to duplicate view for %s.", connection.getServerName()), ex);
}
}
});

this.tabbedPane.addTab(connection.getServerName(), view.getView());
this.tabbedPane.setSelectedIndex(index);
this.tabbedPane.setTabComponentAt(index, closeButton);
this.tabbedPane.setTabComponentAt(index, tab);

ViewConfig.instance().addCluster(connection.getServerName());
if (views.size() == 1) {
ViewConfig.instance().addCluster(connection.getServerName());
}

view.populate();
return view;
}

/**
Expand Down
37 changes: 23 additions & 14 deletions src/main/java/hrider/ui/views/DesignerView.java
Expand Up @@ -1002,10 +1002,28 @@ public void populate() {
loadTables();
}

/**
* Gets the currently selected table name.
*
* @return The name of the selected table from the list of the tables.
*/
public String getSelectedTableName() {
return (String)this.tablesList.getSelectedValue();
}

/**
* Selects a table from the list of the available tables.
*
* @param tableName The name of the table to select.
*/
public void setSelectedTableName(String tableName) {
this.tablesList.setSelectedValue(tableName, true);
}

/**
* Gets the reference to the view.
*
* @return A {@link javax.swing.JPanel} that contains the controls.
* @return A {@link JPanel} that contains the controls.
*/
public JPanel getView() {
return this.topPanel;
Expand All @@ -1014,7 +1032,7 @@ public JPanel getView() {
/**
* Gets a reference to the class used to access the hbase.
*
* @return A reference to the {@link hrider.hbase.Connection} class.
* @return A reference to the {@link Connection} class.
*/
public Connection getConnection() {
return this.connection;
Expand Down Expand Up @@ -1082,7 +1100,7 @@ private static boolean hasTableInClipboard() {
*
* @param columnName The name of the column to look.
* @param table The table that should contain column.
* @return A reference to {@link javax.swing.table.TableColumn} if found or {@code null} otherwise.
* @return A reference to {@link TableColumn} if found or {@code null} otherwise.
*/
private static TableColumn getColumn(String columnName, JTable table) {
for (int i = 0 ; i < table.getColumnCount() ; i++) {
Expand Down Expand Up @@ -1538,7 +1556,7 @@ private void populateColumnsTable(boolean clearRows, DataRow row) {

/**
* Populates a rows table. The method loads the table content. The number of loaded rows depends on the parameter defined by the user
* in the {@link hrider.ui.views.DesignerView#rowsNumber} control.
* in the {@link DesignerView#rowsNumber} control.
*
* @param direction Defines what rows should be presented to the user. {@link Direction#Current},
* {@link Direction#Forward} or {@link Direction#Backward}.
Expand All @@ -1549,7 +1567,7 @@ private void populateRowsTable(Direction direction) {

/**
* Populates a rows table. The method loads the table content. The number of loaded rows depends on the parameter defined by the user
* in the {@link hrider.ui.views.DesignerView#rowsNumber} control.
* in the {@link DesignerView#rowsNumber} control.
*
* @param offset The first row to start loading from.
* @param direction Defines what rows should be presented to the user. {@link Direction#Current},
Expand Down Expand Up @@ -2086,15 +2104,6 @@ private int getColumnIndex(String columnName) {
return 0;
}

/**
* Gets the currently selected table name.
*
* @return The name of the selected table from the list of the tables.
*/
private String getSelectedTableName() {
return (String)this.tablesList.getSelectedValue();
}

/**
* Gets a list of the selected tables.
*
Expand Down
Binary file added src/main/resources/images/duplicate.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c283f2f

Please sign in to comment.