| /* | |
| * 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.awt.BorderLayout; | |
| import java.awt.Color; | |
| import java.awt.FlowLayout; | |
| import java.awt.Insets; | |
| import java.awt.event.ActionEvent; | |
| import java.awt.event.ActionListener; | |
| import java.awt.event.KeyAdapter; | |
| import java.awt.event.KeyEvent; | |
| import java.awt.event.MouseAdapter; | |
| import java.awt.event.MouseEvent; | |
| import java.io.IOException; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.Map; | |
| import javax.swing.JButton; | |
| import javax.swing.JLabel; | |
| import javax.swing.JOptionPane; | |
| import javax.swing.JPanel; | |
| import javax.swing.JScrollPane; | |
| import javax.swing.JTable; | |
| import javax.swing.JTextField; | |
| import javax.swing.RowFilter; | |
| import javax.swing.SwingConstants; | |
| import javax.swing.event.ListSelectionEvent; | |
| import javax.swing.event.ListSelectionListener; | |
| import javax.swing.table.DefaultTableCellRenderer; | |
| import javax.swing.table.TableCellRenderer; | |
| import javax.swing.table.TableRowSorter; | |
| import com.gitblit.Constants; | |
| import com.gitblit.Constants.RpcRequest; | |
| import com.gitblit.Keys; | |
| import com.gitblit.models.FeedModel; | |
| import com.gitblit.models.RegistrantAccessPermission; | |
| import com.gitblit.models.RepositoryModel; | |
| import com.gitblit.utils.StringUtils; | |
| /** | |
| * RSS Feeds Panel displays recent entries and launches the browser to view the | |
| * commit. commitdiff, or tree of a commit. | |
| * | |
| * @author James Moger | |
| * | |
| */ | |
| public abstract class RepositoriesPanel extends JPanel { | |
| private static final long serialVersionUID = 1L; | |
| private final GitblitClient gitblit; | |
| private HeaderPanel header; | |
| private JTable table; | |
| private RepositoriesTableModel tableModel; | |
| private TableRowSorter<RepositoriesTableModel> defaultSorter; | |
| private JButton createRepository; | |
| private JButton editRepository; | |
| private JButton delRepository; | |
| private JTextField filterTextfield; | |
| private JButton clearCache; | |
| public RepositoriesPanel(GitblitClient gitblit) { | |
| super(); | |
| this.gitblit = gitblit; | |
| initialize(); | |
| } | |
| private void initialize() { | |
| final JButton browseRepository = new JButton(Translation.get("gb.browse")); | |
| browseRepository.setEnabled(false); | |
| browseRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| RepositoryModel model = getSelectedRepositories().get(0); | |
| String url = gitblit.getURL("summary", model.name, null); | |
| Utils.browse(url); | |
| } | |
| }); | |
| JButton refreshRepositories = new JButton(Translation.get("gb.refresh")); | |
| refreshRepositories.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| refreshRepositories(); | |
| } | |
| }); | |
| clearCache = new JButton(Translation.get("gb.clearCache")); | |
| clearCache.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| clearCache(); | |
| } | |
| }); | |
| createRepository = new JButton(Translation.get("gb.create")); | |
| createRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| createRepository(); | |
| } | |
| }); | |
| editRepository = new JButton(Translation.get("gb.edit")); | |
| editRepository.setEnabled(false); | |
| editRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| editRepository(getSelectedRepositories().get(0)); | |
| } | |
| }); | |
| delRepository = new JButton(Translation.get("gb.delete")); | |
| delRepository.setEnabled(false); | |
| delRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| deleteRepositories(getSelectedRepositories()); | |
| } | |
| }); | |
| final JButton subscribeRepository = new JButton(Translation.get("gb.subscribe") + "..."); | |
| subscribeRepository.setEnabled(false); | |
| subscribeRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| List<FeedModel> feeds = gitblit.getAvailableFeeds(getSelectedRepositories().get(0)); | |
| subscribeFeeds(feeds); | |
| } | |
| }); | |
| final JButton logRepository = new JButton(Translation.get("gb.log") + "..."); | |
| logRepository.setEnabled(false); | |
| logRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| RepositoryModel model = getSelectedRepositories().get(0); | |
| showSearchDialog(false, model); | |
| } | |
| }); | |
| final JButton searchRepository = new JButton(Translation.get("gb.search") + "..."); | |
| searchRepository.setEnabled(false); | |
| searchRepository.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| RepositoryModel model = getSelectedRepositories().get(0); | |
| showSearchDialog(true, model); | |
| } | |
| }); | |
| SubscribedRepositoryRenderer nameRenderer = new SubscribedRepositoryRenderer(gitblit); | |
| IndicatorsRenderer typeRenderer = new IndicatorsRenderer(); | |
| DefaultTableCellRenderer sizeRenderer = new DefaultTableCellRenderer(); | |
| sizeRenderer.setHorizontalAlignment(SwingConstants.RIGHT); | |
| sizeRenderer.setForeground(new Color(0, 0x80, 0)); | |
| DefaultTableCellRenderer ownerRenderer = new DefaultTableCellRenderer(); | |
| ownerRenderer.setForeground(Color.gray); | |
| ownerRenderer.setHorizontalAlignment(SwingConstants.CENTER); | |
| tableModel = new RepositoriesTableModel(); | |
| defaultSorter = new TableRowSorter<RepositoriesTableModel>(tableModel); | |
| table = Utils.newTable(tableModel, Utils.DATE_FORMAT); | |
| table.setRowSorter(defaultSorter); | |
| table.getRowSorter().toggleSortOrder(RepositoriesTableModel.Columns.Name.ordinal()); | |
| setRepositoryRenderer(RepositoriesTableModel.Columns.Name, nameRenderer, -1); | |
| setRepositoryRenderer(RepositoriesTableModel.Columns.Indicators, typeRenderer, 100); | |
| setRepositoryRenderer(RepositoriesTableModel.Columns.Owner, ownerRenderer, -1); | |
| setRepositoryRenderer(RepositoriesTableModel.Columns.Size, sizeRenderer, 60); | |
| table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { | |
| @Override | |
| public void valueChanged(ListSelectionEvent e) { | |
| if (e.getValueIsAdjusting()) { | |
| return; | |
| } | |
| boolean singleSelection = table.getSelectedRowCount() == 1; | |
| boolean selected = table.getSelectedRow() > -1; | |
| if (singleSelection) { | |
| RepositoryModel repository = getSelectedRepositories().get(0); | |
| browseRepository.setEnabled(repository.hasCommits); | |
| logRepository.setEnabled(repository.hasCommits); | |
| searchRepository.setEnabled(repository.hasCommits); | |
| subscribeRepository.setEnabled(repository.hasCommits); | |
| } else { | |
| browseRepository.setEnabled(false); | |
| logRepository.setEnabled(false); | |
| searchRepository.setEnabled(false); | |
| subscribeRepository.setEnabled(false); | |
| } | |
| delRepository.setEnabled(selected); | |
| if (selected) { | |
| int viewRow = table.getSelectedRow(); | |
| int modelRow = table.convertRowIndexToModel(viewRow); | |
| RepositoryModel model = ((RepositoriesTableModel) table.getModel()).list | |
| .get(modelRow); | |
| editRepository.setEnabled(singleSelection | |
| && (gitblit.allowManagement() || gitblit.isOwner(model))); | |
| } else { | |
| editRepository.setEnabled(false); | |
| } | |
| } | |
| }); | |
| table.addMouseListener(new MouseAdapter() { | |
| @Override | |
| public void mouseClicked(MouseEvent e) { | |
| if (e.getClickCount() == 2 && gitblit.allowManagement()) { | |
| editRepository(getSelectedRepositories().get(0)); | |
| } | |
| } | |
| }); | |
| filterTextfield = new JTextField(); | |
| filterTextfield.addActionListener(new ActionListener() { | |
| @Override | |
| public void actionPerformed(ActionEvent e) { | |
| filterRepositories(filterTextfield.getText()); | |
| } | |
| }); | |
| filterTextfield.addKeyListener(new KeyAdapter() { | |
| @Override | |
| public void keyReleased(KeyEvent e) { | |
| filterRepositories(filterTextfield.getText()); | |
| } | |
| }); | |
| JPanel repositoryFilterPanel = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN)); | |
| repositoryFilterPanel.add(new JLabel(Translation.get("gb.filter")), BorderLayout.WEST); | |
| repositoryFilterPanel.add(filterTextfield, BorderLayout.CENTER); | |
| JPanel repositoryTablePanel = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN)); | |
| repositoryTablePanel.add(repositoryFilterPanel, BorderLayout.NORTH); | |
| repositoryTablePanel.add(new JScrollPane(table), BorderLayout.CENTER); | |
| JPanel repositoryControls = new JPanel(new FlowLayout(FlowLayout.CENTER, Utils.MARGIN, 0)); | |
| repositoryControls.add(clearCache); | |
| repositoryControls.add(refreshRepositories); | |
| repositoryControls.add(browseRepository); | |
| repositoryControls.add(createRepository); | |
| repositoryControls.add(editRepository); | |
| repositoryControls.add(delRepository); | |
| repositoryControls.add(subscribeRepository); | |
| repositoryControls.add(logRepository); | |
| repositoryControls.add(searchRepository); | |
| setLayout(new BorderLayout(Utils.MARGIN, Utils.MARGIN)); | |
| header = new HeaderPanel(Translation.get("gb.repositories"), "git-orange-16x16.png"); | |
| add(header, BorderLayout.NORTH); | |
| add(repositoryTablePanel, BorderLayout.CENTER); | |
| add(repositoryControls, BorderLayout.SOUTH); | |
| } | |
| @Override | |
| public void requestFocus() { | |
| filterTextfield.requestFocus(); | |
| } | |
| @Override | |
| public Insets getInsets() { | |
| return Utils.INSETS; | |
| } | |
| private void setRepositoryRenderer(RepositoriesTableModel.Columns col, | |
| TableCellRenderer renderer, int maxWidth) { | |
| String name = table.getColumnName(col.ordinal()); | |
| table.getColumn(name).setCellRenderer(renderer); | |
| if (maxWidth > 0) { | |
| table.getColumn(name).setMinWidth(maxWidth); | |
| table.getColumn(name).setMaxWidth(maxWidth); | |
| } | |
| } | |
| protected abstract void subscribeFeeds(List<FeedModel> feeds); | |
| protected abstract void updateUsersTable(); | |
| protected abstract void updateTeamsTable(); | |
| protected void disableManagement() { | |
| clearCache.setVisible(false); | |
| createRepository.setVisible(false); | |
| editRepository.setVisible(false); | |
| delRepository.setVisible(false); | |
| } | |
| protected void updateTable(boolean pack) { | |
| tableModel.list.clear(); | |
| tableModel.list.addAll(gitblit.getRepositories()); | |
| tableModel.fireTableDataChanged(); | |
| header.setText(Translation.get("gb.repositories") + " (" + gitblit.getRepositories().size() | |
| + ")"); | |
| if (pack) { | |
| Utils.packColumns(table, Utils.MARGIN); | |
| } | |
| } | |
| private void filterRepositories(final String fragment) { | |
| if (StringUtils.isEmpty(fragment)) { | |
| table.setRowSorter(defaultSorter); | |
| return; | |
| } | |
| RowFilter<RepositoriesTableModel, Object> containsFilter = new RowFilter<RepositoriesTableModel, Object>() { | |
| @Override | |
| public boolean include(Entry<? extends RepositoriesTableModel, ? 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<RepositoriesTableModel> sorter = new TableRowSorter<RepositoriesTableModel>( | |
| tableModel); | |
| sorter.setRowFilter(containsFilter); | |
| table.setRowSorter(sorter); | |
| } | |
| private List<RepositoryModel> getSelectedRepositories() { | |
| List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(); | |
| for (int viewRow : table.getSelectedRows()) { | |
| int modelRow = table.convertRowIndexToModel(viewRow); | |
| RepositoryModel model = tableModel.list.get(modelRow); | |
| repositories.add(model); | |
| } | |
| return repositories; | |
| } | |
| protected void refreshRepositories() { | |
| GitblitWorker worker = new GitblitWorker(RepositoriesPanel.this, | |
| RpcRequest.LIST_REPOSITORIES) { | |
| @Override | |
| protected Boolean doRequest() throws IOException { | |
| gitblit.refreshRepositories(); | |
| return true; | |
| } | |
| @Override | |
| protected void onSuccess() { | |
| updateTable(false); | |
| } | |
| }; | |
| worker.execute(); | |
| } | |
| protected void clearCache() { | |
| GitblitWorker worker = new GitblitWorker(RepositoriesPanel.this, | |
| RpcRequest.CLEAR_REPOSITORY_CACHE) { | |
| @Override | |
| protected Boolean doRequest() throws IOException { | |
| if (gitblit.clearRepositoryCache()) { | |
| gitblit.refreshRepositories(); | |
| return true; | |
| } | |
| return false; | |
| } | |
| @Override | |
| protected void onSuccess() { | |
| updateTable(false); | |
| } | |
| }; | |
| worker.execute(); | |
| } | |
| /** | |
| * Displays the create repository dialog and fires a SwingWorker to update | |
| * the server, if appropriate. | |
| * | |
| */ | |
| protected void createRepository() { | |
| EditRepositoryDialog dialog = new EditRepositoryDialog(gitblit.getProtocolVersion()); | |
| dialog.setLocationRelativeTo(RepositoriesPanel.this); | |
| dialog.setAccessRestriction(gitblit.getDefaultAccessRestriction()); | |
| dialog.setAuthorizationControl(gitblit.getDefaultAuthorizationControl()); | |
| dialog.setUsers(null, gitblit.getUsernames(), null); | |
| dialog.setTeams(gitblit.getTeamnames(), null); | |
| dialog.setRepositories(gitblit.getRepositories()); | |
| dialog.setFederationSets(gitblit.getFederationSets(), null); | |
| dialog.setIndexedBranches(new ArrayList<String>(Arrays.asList(Constants.DEFAULT_BRANCH)), null); | |
| dialog.setPreReceiveScripts(gitblit.getPreReceiveScriptsUnused(null), | |
| gitblit.getPreReceiveScriptsInherited(null), null); | |
| dialog.setPostReceiveScripts(gitblit.getPostReceiveScriptsUnused(null), | |
| gitblit.getPostReceiveScriptsInherited(null), null); | |
| dialog.setVisible(true); | |
| final RepositoryModel newRepository = dialog.getRepository(); | |
| final List<RegistrantAccessPermission> permittedUsers = dialog.getUserAccessPermissions(); | |
| final List<RegistrantAccessPermission> permittedTeams = dialog.getTeamAccessPermissions(); | |
| if (newRepository == null) { | |
| return; | |
| } | |
| GitblitWorker worker = new GitblitWorker(this, RpcRequest.CREATE_REPOSITORY) { | |
| @Override | |
| protected Boolean doRequest() throws IOException { | |
| boolean success = gitblit.createRepository(newRepository, permittedUsers, | |
| permittedTeams); | |
| if (success) { | |
| gitblit.refreshRepositories(); | |
| if (permittedUsers.size() > 0) { | |
| gitblit.refreshUsers(); | |
| } | |
| if (permittedTeams.size() > 0) { | |
| gitblit.refreshTeams(); | |
| } | |
| } | |
| return success; | |
| } | |
| @Override | |
| protected void onSuccess() { | |
| updateTable(false); | |
| updateUsersTable(); | |
| updateTeamsTable(); | |
| } | |
| @Override | |
| protected void onFailure() { | |
| showFailure("Failed to execute request \"{0}\" for repository \"{1}\".", | |
| getRequestType(), newRepository.name); | |
| } | |
| }; | |
| worker.execute(); | |
| } | |
| /** | |
| * Displays the edit repository dialog and fires a SwingWorker to update the | |
| * server, if appropriate. | |
| * | |
| * @param repository | |
| */ | |
| protected void editRepository(final RepositoryModel repository) { | |
| EditRepositoryDialog dialog = new EditRepositoryDialog(gitblit.getProtocolVersion(), | |
| repository); | |
| dialog.setLocationRelativeTo(RepositoriesPanel.this); | |
| List<String> usernames = gitblit.getUsernames(); | |
| List<RegistrantAccessPermission> members = gitblit.getUserAccessPermissions(repository); | |
| dialog.setUsers(new ArrayList<String>(repository.owners), usernames, members); | |
| dialog.setTeams(gitblit.getTeamnames(), gitblit.getTeamAccessPermissions(repository)); | |
| dialog.setRepositories(gitblit.getRepositories()); | |
| dialog.setFederationSets(gitblit.getFederationSets(), repository.federationSets); | |
| List<String> allLocalBranches = new ArrayList<String>(); | |
| allLocalBranches.add(Constants.DEFAULT_BRANCH); | |
| allLocalBranches.addAll(repository.getLocalBranches()); | |
| dialog.setIndexedBranches(allLocalBranches, repository.indexedBranches); | |
| dialog.setPreReceiveScripts(gitblit.getPreReceiveScriptsUnused(repository), | |
| gitblit.getPreReceiveScriptsInherited(repository), repository.preReceiveScripts); | |
| dialog.setPostReceiveScripts(gitblit.getPostReceiveScriptsUnused(repository), | |
| gitblit.getPostReceiveScriptsInherited(repository), repository.postReceiveScripts); | |
| if (gitblit.getSettings().hasKey(Keys.groovy.customFields)) { | |
| Map<String, String> map = gitblit.getSettings().get(Keys.groovy.customFields).getMap(); | |
| dialog.setCustomFields(repository, map); | |
| } | |
| dialog.setVisible(true); | |
| final RepositoryModel revisedRepository = dialog.getRepository(); | |
| final List<RegistrantAccessPermission> permittedUsers = dialog.getUserAccessPermissions(); | |
| final List<RegistrantAccessPermission> permittedTeams = dialog.getTeamAccessPermissions(); | |
| if (revisedRepository == null) { | |
| return; | |
| } | |
| GitblitWorker worker = new GitblitWorker(this, RpcRequest.EDIT_REPOSITORY) { | |
| @Override | |
| protected Boolean doRequest() throws IOException { | |
| boolean success = gitblit.updateRepository(repository.name, revisedRepository, | |
| permittedUsers, permittedTeams); | |
| if (success) { | |
| gitblit.refreshRepositories(); | |
| gitblit.refreshUsers(); | |
| gitblit.refreshTeams(); | |
| } | |
| return success; | |
| } | |
| @Override | |
| protected void onSuccess() { | |
| updateTable(false); | |
| updateUsersTable(); | |
| updateTeamsTable(); | |
| } | |
| @Override | |
| protected void onFailure() { | |
| showFailure("Failed to execute request \"{0}\" for repository \"{1}\".", | |
| getRequestType(), repository.name); | |
| } | |
| }; | |
| worker.execute(); | |
| } | |
| protected void deleteRepositories(final List<RepositoryModel> repositories) { | |
| if (repositories == null || repositories.size() == 0) { | |
| return; | |
| } | |
| StringBuilder message = new StringBuilder("Delete the following repositories?\n\n"); | |
| for (RepositoryModel repository : repositories) { | |
| message.append(repository.name).append("\n"); | |
| } | |
| int result = JOptionPane.showConfirmDialog(RepositoriesPanel.this, message.toString(), | |
| "Delete Repositories?", JOptionPane.YES_NO_OPTION); | |
| if (result == JOptionPane.YES_OPTION) { | |
| GitblitWorker worker = new GitblitWorker(this, RpcRequest.DELETE_REPOSITORY) { | |
| @Override | |
| protected Boolean doRequest() throws IOException { | |
| boolean success = true; | |
| for (RepositoryModel repository : repositories) { | |
| success &= gitblit.deleteRepository(repository); | |
| } | |
| if (success) { | |
| gitblit.refreshRepositories(); | |
| gitblit.refreshUsers(); | |
| gitblit.refreshTeams(); | |
| } | |
| return success; | |
| } | |
| @Override | |
| protected void onSuccess() { | |
| updateTable(false); | |
| updateUsersTable(); | |
| updateTeamsTable(); | |
| } | |
| @Override | |
| protected void onFailure() { | |
| showFailure("Failed to delete specified repositories!"); | |
| } | |
| }; | |
| worker.execute(); | |
| } | |
| } | |
| private void showSearchDialog(boolean isSearch, final RepositoryModel repository) { | |
| final SearchDialog dialog = new SearchDialog(gitblit, isSearch); | |
| if (repository != null) { | |
| dialog.selectRepository(repository); | |
| } | |
| dialog.setLocationRelativeTo(this); | |
| dialog.setVisible(true); | |
| } | |
| } |