James Moger
2011-10-18 ee25c8391c07dc59dc7cb9b3ff8b1b30dcbd2fcd
Added icons and polish. Save and load gitblit registrations.
2 files added
6 files modified
402 ■■■■■ changed files
build.xml 3 ●●●●● patch | view | raw | blame | history
resources/settings_16x16.png patch | view | raw | blame | history
src/com/gitblit/client/GitblitManager.java 131 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/GitblitPanel.java 143 ●●●● patch | view | raw | blame | history
src/com/gitblit/client/HeaderPanel.java 13 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/SettingsModel.java 110 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/Utils.java 1 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.properties 1 ●●●● patch | view | raw | blame | history
build.xml
@@ -428,6 +428,9 @@
        <genjar jarfile="manager.jar">
            <resource file="${basedir}/src/com/gitblit/client/splash.png" />
            <resource file="${basedir}/resources/gitblt-favicon.png" />
            <resource file="${basedir}/resources/gitweb-favicon.png" />
            <resource file="${basedir}/resources/user_16x16.png" />
            <resource file="${basedir}/resources/settings_16x16.png" />
            <resource file="${basedir}/resources/lock_go_16x16.png" />
            <resource file="${basedir}/resources/lock_pull_16x16.png" />
            <resource file="${basedir}/resources/shield_16x16.png" />
resources/settings_16x16.png
src/com/gitblit/client/GitblitManager.java
@@ -20,12 +20,18 @@
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.text.MessageFormat;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
@@ -41,11 +47,17 @@
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.Base64;
import org.eclipse.jgit.util.FS;
import com.gitblit.Constants;
import com.gitblit.utils.StringUtils;
/**
 * Sample RPC application.
 * Gitblit Manager issues JSON RPC requests to a Gitblit server.
 * 
 * @author James Moger
 * 
@@ -54,10 +66,11 @@
    private static final long serialVersionUID = 1L;
    private JTabbedPane serverTabs;
    private File configFile = new File(System.getProperty("user.home"), ".gitblit/config");
    private GitblitRegistration localhost = new GitblitRegistration("default",
            "https://localhost:8443", "admin", "admin".toCharArray());
    private List<GitblitRegistration> registrations = new ArrayList<GitblitRegistration>();
    private Map<String, GitblitRegistration> registrations = new LinkedHashMap<String, GitblitRegistration>();
    private JMenu recentMenu;
    private GitblitManager() {
@@ -67,10 +80,66 @@
    private void initialize() {
        setContentPane(getCenterPanel());
        setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage());
        setTitle("Gitblit Manager v" + Constants.VERSION + " (" + Constants.VERSION_DATE + ")");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 500);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                saveSizeAndPosition();
            }
        });
        setSizeAndPosition();
        loadRegistrations();
        rebuildRecentMenu();
    }
    private void setSizeAndPosition() {
        String sz = null;
        String pos = null;
        try {
            StoredConfig config = getConfig();
            sz = config.getString("ui", null, "size");
            pos = config.getString("ui", null, "position");
        } catch (Throwable t) {
            t.printStackTrace();
        }
        // try to restore saved window size
        if (StringUtils.isEmpty(sz)) {
            setSize(850, 500);
        } else {
            String[] chunks = sz.split("x");
            int width = Integer.parseInt(chunks[0]);
            int height = Integer.parseInt(chunks[1]);
            setSize(width, height);
        }
        // try to restore saved window position
        if (StringUtils.isEmpty(pos)) {
            setLocationRelativeTo(null);
        } else {
            String[] chunks = pos.split(",");
            int x = Integer.parseInt(chunks[0]);
            int y = Integer.parseInt(chunks[1]);
            setLocation(x, y);
        }
    }
    private void saveSizeAndPosition() {
        try {
            // save window size and position
            StoredConfig config = getConfig();
            Dimension sz = GitblitManager.this.getSize();
            config.setString("ui", null, "size",
                    MessageFormat.format("{0,number,0}x{1,number,0}", sz.width, sz.height));
            Point pos = GitblitManager.this.getLocationOnScreen();
            config.setString("ui", null, "position",
                    MessageFormat.format("{0,number,0},{1,number,0}", pos.x, pos.y));
            config.save();
        } catch (Throwable t) {
            Utils.showException(GitblitManager.this, t);
        }
    }
    public void setVisible(boolean value) {
@@ -80,10 +149,10 @@
                loginPrompt(localhost);
            } else if (registrations.size() == 1) {
                // single registration prompt
                loginPrompt(registrations.get(0));
                GitblitRegistration reg = registrations.values().iterator().next();
                loginPrompt(reg);
            }
            super.setVisible(value);
            setLocationRelativeTo(null);
        }
    }
@@ -147,7 +216,7 @@
        reg = new GitblitRegistration(nameField.getText(), url, accountField.getText(),
                passwordField.getPassword());
        boolean success = login(reg);
        registrations.add(0, reg);
        registrations.put(reg.name, reg);
        rebuildRecentMenu();
        return success;
    }
@@ -161,6 +230,7 @@
            serverTabs.setSelectedIndex(idx);
            serverTabs.setTabComponentAt(idx, new ClosableTabComponent(reg.name, null, serverTabs,
                    panel));
            saveRegistration(reg);
            return true;
        } catch (IOException e) {
            JOptionPane.showMessageDialog(GitblitManager.this, e.getMessage(),
@@ -171,17 +241,54 @@
    private void rebuildRecentMenu() {
        recentMenu.removeAll();
        for (final GitblitRegistration reg : registrations) {
            JMenuItem item = new JMenuItem(reg.name);
        ImageIcon icon = new ImageIcon(getClass().getResource("/gitblt-favicon.png"));
        for (final GitblitRegistration reg : registrations.values()) {
            JMenuItem item = new JMenuItem(reg.name, icon);
            item.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    login(reg);
                    loginPrompt(reg);
                }
            });
            recentMenu.add(item);
        }
    }
    private void loadRegistrations() {
        try {
            StoredConfig config = getConfig();
            Set<String> servers = config.getSubsections("servers");
            for (String server : servers) {
                String url = config.getString("servers", server, "url");
                String account = config.getString("servers", server, "account");
                char[] password = new String(Base64.decode(config.getString("servers", server,
                        "password"))).toCharArray();
                GitblitRegistration reg = new GitblitRegistration(server, url, account, password);
                registrations.put(reg.name, reg);
            }
        } catch (Throwable t) {
            Utils.showException(GitblitManager.this, t);
        }
    }
    private void saveRegistration(GitblitRegistration reg) {
        try {
            StoredConfig config = getConfig();
            config.setString("servers", reg.name, "url", reg.url);
            config.setString("servers", reg.name, "account", reg.account);
            config.setString("servers", reg.name, "password",
                    Base64.encodeBytes(new String(reg.password).getBytes("UTF-8")));
            config.save();
        } catch (Throwable t) {
            Utils.showException(GitblitManager.this, t);
        }
    }
    private StoredConfig getConfig() throws IOException, ConfigInvalidException {
        FileBasedConfig config = new FileBasedConfig(configFile, FS.detect());
        config.load();
        return config;
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
src/com/gitblit/client/GitblitPanel.java
@@ -80,6 +80,10 @@
    private UsersModel usersModel;
    private JTable settingsTable;
    private SettingsModel settingsModel;
    private JButton createRepository;
    private JButton delRepository;
@@ -96,6 +100,8 @@
    private TableRowSorter<UsersModel> defaultUsersSorter;
    private TableRowSorter<SettingsModel> defaultSettingsSorter;
    private JButton editRepository;
    public GitblitPanel(GitblitRegistration reg) {
@@ -105,6 +111,17 @@
    public GitblitPanel(String url, String account, char[] password) {
        this.gitblit = new GitblitModel(url, account, password);
        tabs = new JTabbedPane(JTabbedPane.BOTTOM);
        tabs.addTab(Translation.get("gb.repositories"), createRepositoriesPanel());
        tabs.addTab(Translation.get("gb.users"), createUsersPanel());
        tabs.addTab(Translation.get("gb.federation"), new JPanel());
        tabs.addTab(Translation.get("gb.settings"), createSettingsPanel());
        setLayout(new BorderLayout());
        add(tabs, BorderLayout.CENTER);
    }
    private JPanel createRepositoriesPanel() {
        final JButton browseRepository = new JButton(Translation.get("gb.browse"));
        browseRepository.setEnabled(false);
        browseRepository.addActionListener(new ActionListener() {
@@ -168,10 +185,10 @@
        repositoriesTable.setRowSorter(defaultRepositoriesSorter);
        repositoriesTable.getRowSorter().toggleSortOrder(RepositoriesModel.Columns.Name.ordinal());
        setRepositoryRenderer(RepositoriesModel.Columns.Name, nameRenderer);
        setRepositoryRenderer(RepositoriesModel.Columns.Indicators, typeRenderer);
        setRepositoryRenderer(RepositoriesModel.Columns.Owner, ownerRenderer);
        setRepositoryRenderer(RepositoriesModel.Columns.Size, sizeRenderer);
        setRepositoryRenderer(RepositoriesModel.Columns.Name, nameRenderer, -1);
        setRepositoryRenderer(RepositoriesModel.Columns.Indicators, typeRenderer, 100);
        setRepositoryRenderer(RepositoriesModel.Columns.Owner, ownerRenderer, -1);
        setRepositoryRenderer(RepositoriesModel.Columns.Size, sizeRenderer, 60);
        repositoriesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
@@ -231,11 +248,25 @@
                return insets;
            }
        };
        repositoriesPanel.add(new HeaderPanel(Translation.get("gb.repositories")),
                BorderLayout.NORTH);
        repositoriesPanel.add(new HeaderPanel(Translation.get("gb.repositories"),
                "gitweb-favicon.png"), BorderLayout.NORTH);
        repositoriesPanel.add(repositoryTablePanel, BorderLayout.CENTER);
        repositoriesPanel.add(repositoryControls, BorderLayout.SOUTH);
        return repositoriesPanel;
    }
    private void setRepositoryRenderer(RepositoriesModel.Columns col, TableCellRenderer renderer,
            int maxWidth) {
        String name = repositoriesTable.getColumnName(col.ordinal());
        repositoriesTable.getColumn(name).setCellRenderer(renderer);
        if (maxWidth > 0) {
            repositoriesTable.getColumn(name).setMinWidth(maxWidth);
            repositoriesTable.getColumn(name).setMaxWidth(maxWidth);
        }
    }
    private JPanel createUsersPanel() {
        JButton refreshUsers = new JButton(Translation.get("gb.refresh"));
        refreshUsers.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
@@ -322,22 +353,73 @@
                return insets;
            }
        };
        usersPanel.add(new HeaderPanel(Translation.get("gb.users")), BorderLayout.NORTH);
        usersPanel.add(new HeaderPanel(Translation.get("gb.users"), "user_16x16.png"),
                BorderLayout.NORTH);
        usersPanel.add(userTablePanel, BorderLayout.CENTER);
        usersPanel.add(userControls, BorderLayout.SOUTH);
        tabs = new JTabbedPane(JTabbedPane.BOTTOM);
        tabs.addTab(Translation.get("gb.repositories"), repositoriesPanel);
        tabs.addTab(Translation.get("gb.users"), usersPanel);
        tabs.addTab(Translation.get("gb.federation"), new JPanel());
        setLayout(new BorderLayout());
        add(tabs, BorderLayout.CENTER);
        return usersPanel;
    }
    private void setRepositoryRenderer(RepositoriesModel.Columns col, TableCellRenderer renderer) {
        String name = repositoriesTable.getColumnName(col.ordinal());
        repositoriesTable.getColumn(name).setCellRenderer(renderer);
    private JPanel createSettingsPanel() {
        settingsModel = new SettingsModel();
        defaultSettingsSorter = new TableRowSorter<SettingsModel>(settingsModel);
        settingsTable = Utils.newTable(settingsModel);
        String name = settingsTable.getColumnName(UsersModel.Columns.Name.ordinal());
        settingsTable.setRowHeight(nameRenderer.getFont().getSize() + 8);
        settingsTable.getColumn(name).setCellRenderer(nameRenderer);
        settingsTable.setRowSorter(defaultSettingsSorter);
        settingsTable.getRowSorter().toggleSortOrder(SettingsModel.Columns.Name.ordinal());
        settingsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting()) {
                    return;
                }
                boolean selected = settingsTable.getSelectedRow() > -1;
                boolean singleSelection = settingsTable.getSelectedRows().length == 1;
                // TODO enable/disable setting buttons
            }
        });
        final JTextField settingFilter = new JTextField();
        settingFilter.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                filterSettings(settingFilter.getText());
            }
        });
        settingFilter.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                filterSettings(settingFilter.getText());
            }
        });
        JPanel settingFilterPanel = new JPanel(new BorderLayout(margin, margin));
        settingFilterPanel.add(new JLabel(Translation.get("gb.filter")), BorderLayout.WEST);
        settingFilterPanel.add(settingFilter, BorderLayout.CENTER);
        JPanel settingsTablePanel = new JPanel(new BorderLayout(margin, margin));
        settingsTablePanel.add(settingFilterPanel, BorderLayout.NORTH);
        settingsTablePanel.add(new JScrollPane(settingsTable), BorderLayout.CENTER);
        JPanel settingsControls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
        // TODO update setting?
        JPanel settingsPanel = new JPanel(new BorderLayout(margin, margin)) {
            private static final long serialVersionUID = 1L;
            public Insets getInsets() {
                return insets;
            }
        };
        settingsPanel.add(new HeaderPanel(Translation.get("gb.settings"), "settings_16x16.png"),
                BorderLayout.NORTH);
        settingsPanel.add(settingsTablePanel, BorderLayout.CENTER);
        settingsPanel.add(settingsControls, BorderLayout.SOUTH);
        return settingsPanel;
    }
    public void login() throws IOException {
@@ -348,6 +430,7 @@
        if (gitblit.allowAdmin()) {
            updateUsersTable();
            updateSettingsTable();
        } else {
            // user does not have administrator privileges
            // hide admin repository buttons
@@ -372,6 +455,11 @@
        usersModel.list.clear();
        usersModel.list.addAll(gitblit.getUsers());
        usersModel.fireTableDataChanged();
    }
    private void updateSettingsTable() {
        settingsModel.setSettings(gitblit.getSettings());
        settingsModel.fireTableDataChanged();
    }
    private void filterRepositories(final String fragment) {
@@ -413,6 +501,26 @@
        TableRowSorter<UsersModel> sorter = new TableRowSorter<UsersModel>(usersModel);
        sorter.setRowFilter(containsFilter);
        usersTable.setRowSorter(sorter);
    }
    private void filterSettings(final String fragment) {
        if (StringUtils.isEmpty(fragment)) {
            settingsTable.setRowSorter(defaultSettingsSorter);
            return;
        }
        RowFilter<SettingsModel, Object> containsFilter = new RowFilter<SettingsModel, Object>() {
            public boolean include(Entry<? extends SettingsModel, ? extends Object> entry) {
                for (int i = entry.getValueCount() - 1; i >= 0; i--) {
                    if (entry.getStringValue(i).toLowerCase().contains(fragment.toLowerCase())) {
                        return true;
                    }
                }
                return false;
            }
        };
        TableRowSorter<SettingsModel> sorter = new TableRowSorter<SettingsModel>(settingsModel);
        sorter.setRowFilter(containsFilter);
        settingsTable.setRowSorter(sorter);
    }
    private List<RepositoryModel> getSelectedRepositories() {
@@ -572,6 +680,7 @@
                        success &= gitblit.deleteRepository(repository);
                    }
                    if (success) {
                        gitblit.refreshRepositories();
                        gitblit.refreshUsers();
                    }
                    return success;
src/com/gitblit/client/HeaderPanel.java
@@ -15,6 +15,7 @@
 */
package com.gitblit.client;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
@@ -24,8 +25,11 @@
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.gitblit.utils.StringUtils;
public class HeaderPanel extends JPanel {
@@ -33,12 +37,15 @@
    private Color lightColor = new Color(0, 0, 0x60);
    public HeaderPanel(String text) {
    public HeaderPanel(String text, String icon) {
        super(new FlowLayout(FlowLayout.LEFT), true);
        setOpaque(true);
        setBackground(new Color(0, 0, 0x20));
        JLabel label = new JLabel(text);
        if (!StringUtils.isEmpty(icon)) {
            label.setIcon(new ImageIcon(getClass().getResource("/" + icon)));
        }
        label.setForeground(Color.white);
        label.setFont(label.getFont().deriveFont(14f));
        add(label);
@@ -53,5 +60,9 @@
                false);
        g.setPaint(gradientPaint);
        g.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
        g.setColor(new Color(0xff, 0x99, 0x00));
        int stroke = 2;
        g.setStroke(new BasicStroke(stroke));
        g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
    }
}
src/com/gitblit/client/SettingsModel.java
New file
@@ -0,0 +1,110 @@
/*
 * Copyright 2011 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import com.gitblit.IStoredSettings;
/**
 * Table model of IStoredSettings.
 *
 * @author James Moger
 *
 */
public class SettingsModel extends AbstractTableModel {
    private static final long serialVersionUID = 1L;
    IStoredSettings settings;
    List<String> keys;
    enum Columns {
        Name, Value;
        @Override
        public String toString() {
            return name().replace('_', ' ');
        }
    }
    public SettingsModel() {
        this(null);
    }
    public SettingsModel(IStoredSettings settings) {
        setSettings(settings);
    }
    public void setSettings(IStoredSettings settings) {
        this.settings = settings;
        if (settings == null) {
            keys = new ArrayList<String>();
        } else {
            keys = new ArrayList<String>(settings.getAllKeys(null));
            Collections.sort(keys);
        }
    }
    @Override
    public int getRowCount() {
        return keys.size();
    }
    @Override
    public int getColumnCount() {
        return Columns.values().length;
    }
    @Override
    public String getColumnName(int column) {
        Columns col = Columns.values()[column];
        switch (col) {
        case Name:
            return Translation.get("gb.name");
        }
        return "";
    }
    /**
     * Returns <code>Object.class</code> regardless of <code>columnIndex</code>.
     *
     * @param columnIndex
     *            the column being queried
     * @return the Object.class
     */
    public Class<?> getColumnClass(int columnIndex) {
        return String.class;
    }
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        String key = keys.get(rowIndex);
        Columns col = Columns.values()[columnIndex];
        switch (col) {
        case Name:
            return key;
        case Value:
            return settings.getString(key, "");
        }
        return null;
    }
}
src/com/gitblit/client/Utils.java
@@ -56,6 +56,7 @@
    public static void showException(Component c, Throwable t) {
        // TODO show the unexpected exception
        t.printStackTrace();
    }
    public static void packColumns(JTable table, int margin) {
src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -156,3 +156,4 @@
gb.loading = loading
gb.starting = starting
gb.general = general
gb.settings = settings