From 17820f3a1153250a325fed23dfc2da59ce6ba777 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Mon, 31 Oct 2011 22:47:21 -0400 Subject: [PATCH] More feeds work in Manager --- src/com/gitblit/client/SyndicatedEntryTableModel.java | 8 src/com/gitblit/client/GitblitClient.java | 151 +++----- src/com/gitblit/models/FeedModel.java | 96 ++++++ src/com/gitblit/client/FeedsTableModel.java | 126 +++++++ src/com/gitblit/client/GitblitPanel.java | 74 ++-- src/com/gitblit/client/SubscribedRepositoryRenderer.java | 62 +++ src/com/gitblit/utils/RpcUtils.java | 37 + src/com/gitblit/RpcServlet.java | 15 src/com/gitblit/build/Build.java | 6 src/com/gitblit/client/GitblitRegistration.java | 22 + src/com/gitblit/client/SubscriptionsDialog.java | 159 +++++++++ src/com/gitblit/wicket/GitBlitWebApp.properties | 5 src/com/gitblit/client/Translation.java | 42 +- tests/com/gitblit/tests/RpcTests.java | 2 src/com/gitblit/models/RepositoryModel.java | 1 src/com/gitblit/client/NameRenderer.java | 48 -- src/com/gitblit/client/GitblitManager.java | 21 src/com/gitblit/client/BooleanCellRenderer.java | 50 +++ 18 files changed, 702 insertions(+), 223 deletions(-) diff --git a/src/com/gitblit/RpcServlet.java b/src/com/gitblit/RpcServlet.java index b068a39..585770e 100644 --- a/src/com/gitblit/RpcServlet.java +++ b/src/com/gitblit/RpcServlet.java @@ -91,28 +91,31 @@ } result = repositories; } else if (RpcRequest.LIST_BRANCHES.equals(reqType)) { - // list all branches in all repositories accessible to user - Map<String, List<String>> allBranches = new HashMap<String, List<String>>(); + // list all local branches in all repositories accessible to user + Map<String, List<String>> localBranches = new HashMap<String, List<String>>(); List<RepositoryModel> models = GitBlit.self().getRepositoryModels(user); for (RepositoryModel model : models) { if (!model.hasCommits) { // skip empty repository continue; } - // get branches + // get local branches Repository repository = GitBlit.self().getRepository(model.name); List<RefModel> refs = JGitUtils.getLocalBranches(repository, false, -1); - refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1)); + if (model.showRemoteBranches) { + // add remote branches if repository displays them + refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1)); + } if (refs.size() > 0) { List<String> branches = new ArrayList<String>(); for (RefModel ref : refs) { branches.add(ref.getName()); } - allBranches.put(model.name, branches); + localBranches.put(model.name, branches); } repository.close(); } - result = allBranches; + result = localBranches; } else if (RpcRequest.LIST_USERS.equals(reqType)) { // list users List<String> names = GitBlit.self().getAllUsernames(); diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java index 4389eac..ee53ff0 100644 --- a/src/com/gitblit/build/Build.java +++ b/src/com/gitblit/build/Build.java @@ -398,12 +398,6 @@ "46a386136c901748e6a3af67ebde6c22bc6b4524", "e223571d77769cdafde59040da235842f3326453"); - public static final MavenObject SLF4JNOP = new MavenObject("SLF4J NOP", "org/slf4j", - "slf4j-nop", "1.6.1", 4800, 4100, 32300, - "70249094d4e5653b6bdfea46f3a1a4165c1e1993", - "4a8e77f7bf6897a3c3b7fc3acb4c862dfb905baa", - "24b2b46f9025f2db53b5b32143f7832538fa3178"); - public static final MavenObject SLF4LOG4J = new MavenObject("SLF4J LOG4J", "org/slf4j", "slf4j-log4j12", "1.6.1", 9800, 9500, 52400, "bd245d6746cdd4e6203e976e21d597a46f115802", diff --git a/src/com/gitblit/client/BooleanCellRenderer.java b/src/com/gitblit/client/BooleanCellRenderer.java new file mode 100644 index 0000000..c8341df --- /dev/null +++ b/src/com/gitblit/client/BooleanCellRenderer.java @@ -0,0 +1,50 @@ +/* + * 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.Component; +import java.io.Serializable; + +import javax.swing.JCheckBox; +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.TableCellRenderer; + +/** + * Boolean checkbox cell renderer. + * + * @author James Moger + * + */ +public class BooleanCellRenderer extends JCheckBox implements TableCellRenderer, Serializable { + + private static final long serialVersionUID = 1L; + + public BooleanCellRenderer() { + super(); + setOpaque(false); + setHorizontalAlignment(SwingConstants.CENTER); + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, + boolean hasFocus, int row, int column) { + if (value instanceof Boolean) { + boolean checked = (Boolean) value; + this.setSelected(checked); + } + return this; + } +} \ No newline at end of file diff --git a/src/com/gitblit/client/FeedsTableModel.java b/src/com/gitblit/client/FeedsTableModel.java new file mode 100644 index 0000000..a628fc8 --- /dev/null +++ b/src/com/gitblit/client/FeedsTableModel.java @@ -0,0 +1,126 @@ +/* + * 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.models.FeedModel; + +/** + * Table model of a list of available feeds. + * + * @author James Moger + * + */ +public class FeedsTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + List<FeedModel> list; + + enum Columns { + Subscribed, Repository, Branch, Max_Length; + + @Override + public String toString() { + return name().replace('_', ' '); + } + } + + public FeedsTableModel() { + this(new ArrayList<FeedModel>()); + } + + public FeedsTableModel(List<FeedModel> feeds) { + this.list = feeds; + Collections.sort(this.list); + } + + @Override + public int getRowCount() { + return list.size(); + } + + @Override + public int getColumnCount() { + return Columns.values().length; + } + + @Override + public String getColumnName(int column) { + Columns col = Columns.values()[column]; + switch (col) { + case Repository: + return Translation.get("gb.repository"); + case Branch: + return Translation.get("gb.branch"); + } + 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) { + Columns col = Columns.values()[columnIndex]; + switch (col) { + case Subscribed: + return Boolean.class; + case Max_Length: + return Integer.class; + } + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + Columns col = Columns.values()[columnIndex]; + switch (col) { + case Subscribed: + return true; + } + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + FeedModel model = list.get(rowIndex); + Columns col = Columns.values()[columnIndex]; + switch (col) { + case Repository: + return model.repository; + case Branch: + return model.branch; + case Max_Length: + return model.maxRetrieval; + case Subscribed: + return model.subscribed; + } + return null; + } + + public FeedModel get(int modelRow) { + return list.get(modelRow); + } +} diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java index ccde45a..74e0e08 100644 --- a/src/com/gitblit/client/GitblitClient.java +++ b/src/com/gitblit/client/GitblitClient.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -30,13 +31,13 @@ import com.gitblit.GitBlitException.UnknownRequestException; import com.gitblit.Keys; import com.gitblit.models.FederationModel; +import com.gitblit.models.FeedModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; import com.gitblit.models.SyndicatedEntryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.RpcUtils; -import com.gitblit.utils.StringUtils; import com.gitblit.utils.SyndicationUtils; /** @@ -70,7 +71,11 @@ private final List<FederationModel> federationRegistrations; + private final List<FeedModel> availableFeeds; + private final List<SyndicatedEntryModel> syndicatedEntries; + + private final Set<String> subscribedRepositories; private ServerStatus status; @@ -83,10 +88,13 @@ this.allUsers = new ArrayList<UserModel>(); this.allRepositories = new ArrayList<RepositoryModel>(); this.federationRegistrations = new ArrayList<FederationModel>(); + this.availableFeeds = new ArrayList<FeedModel>(); this.syndicatedEntries = new ArrayList<SyndicatedEntryModel>(); + this.subscribedRepositories = new HashSet<String>(); } public void login() throws IOException { + refreshAvailableFeeds(); refreshRepositories(); try { @@ -95,7 +103,7 @@ } catch (IOException e) { e.printStackTrace(); } - + try { // credentials may not have administrator access // or server may have disabled rpc management @@ -155,7 +163,7 @@ allRepositories.clear(); allRepositories.addAll(repositories.values()); Collections.sort(allRepositories); - updateSubscribedStates(); + markSubscribedFeeds(); return allRepositories; } @@ -176,108 +184,69 @@ return status; } + public List<FeedModel> getAvailableFeeds() { + return availableFeeds; + } + + public List<FeedModel> getAvailableFeeds(RepositoryModel repository) { + List<FeedModel> repositoryFeeds = new ArrayList<FeedModel>(); + if (repository == null) { + return repositoryFeeds; + } + for (FeedModel feed : availableFeeds) { + if (feed.repository.equalsIgnoreCase(repository.name)) { + repositoryFeeds.add(feed); + } + } + return repositoryFeeds; + } + + public List<FeedModel> refreshAvailableFeeds() throws IOException { + List<FeedModel> feeds = RpcUtils.getBranchFeeds(url, account, password); + availableFeeds.clear(); + availableFeeds.addAll(feeds); + markSubscribedFeeds(); + return availableFeeds; + } + public List<SyndicatedEntryModel> refreshSubscribedFeeds() throws IOException { - Set<SyndicatedEntryModel> allFeeds = new HashSet<SyndicatedEntryModel>(); - if (reg.feeds != null && reg.feeds.size() > 0) { - for (String feed : reg.feeds) { - String[] values = feed.split(":"); - String repository = values[0]; - String branch = null; - if (values.length > 1) { - branch = values[1]; - } - List<SyndicatedEntryModel> list = SyndicationUtils.readFeed(url, repository, - branch, -1, account, password); - allFeeds.addAll(list); + Set<SyndicatedEntryModel> allEntries = new HashSet<SyndicatedEntryModel>(); + if (reg.feeds.size() > 0) { + for (FeedModel feed : reg.feeds) { + feed.lastRefresh = new Date(); + List<SyndicatedEntryModel> entries = SyndicationUtils.readFeed(url, + feed.repository, feed.branch, feed.maxRetrieval, account, password); + allEntries.addAll(entries); } } syndicatedEntries.clear(); - syndicatedEntries.addAll(allFeeds); + syndicatedEntries.addAll(allEntries); Collections.sort(syndicatedEntries); return syndicatedEntries; } - private void updateSubscribedStates() { - if (reg.feeds != null) { - Set<String> subscribedRepositories = new HashSet<String>(); - for (String feed : reg.feeds) { - if (feed.indexOf(':') > -1) { - // strip branch - subscribedRepositories.add(feed.substring(0, feed.indexOf(':')).toLowerCase()); - } else { - // default branch - subscribedRepositories.add(feed.toLowerCase()); - } - } - // set subscribed flag - for (RepositoryModel repository : allRepositories) { - repository.subscribed = subscribedRepositories.contains(repository.name - .toLowerCase()); + public void updateSubscribedFeeds(List<FeedModel> list) { + reg.updateSubscribedFeeds(list); + markSubscribedFeeds(); + } + + private void markSubscribedFeeds() { + subscribedRepositories.clear(); + for (FeedModel feed : availableFeeds) { + // mark feed in the available list as subscribed + feed.subscribed = reg.feeds.contains(feed); + if (feed.subscribed) { + subscribedRepositories.add(feed.repository.toLowerCase()); } } + } + + public boolean isSubscribed(RepositoryModel repository) { + return subscribedRepositories.contains(repository.name.toLowerCase()); } public List<SyndicatedEntryModel> getSyndicatedEntries() { return syndicatedEntries; - } - - public boolean isSubscribed(RepositoryModel repository, String branch) { - if (reg.feeds != null && reg.feeds.size() > 0) { - for (String feed : reg.feeds) { - String[] values = feed.split(":"); - String repositoryName = values[0]; - if (repository.name.equalsIgnoreCase(repositoryName)) { - return true; - } - // TODO check branch subscriptions - String branchName = null; - if (values.length > 1) { - branchName = values[1]; - } - } - } - return false; - } - - public boolean subscribe(RepositoryModel repository, String branch) { - String feed = repository.name; - if (!StringUtils.isEmpty(branch)) { - feed += ":" + branch; - } - if (reg.feeds == null) { - reg.feeds = new ArrayList<String>(); - } - reg.feeds.add(feed); - updateSubscribedStates(); - return true; - } - - public boolean unsubscribe(RepositoryModel repository, String branch) { - String feed = repository.name; - if (!StringUtils.isEmpty(branch)) { - feed += ":" + branch; - } - reg.feeds.remove(feed); - if (syndicatedEntries.size() > 0) { - List<SyndicatedEntryModel> toRemove = new ArrayList<SyndicatedEntryModel>(); - for (SyndicatedEntryModel model : syndicatedEntries) { - if (model.repository.equalsIgnoreCase(repository.name)) { - boolean emptyUnsubscribeBranch = StringUtils.isEmpty(branch); - boolean emptyFromBranch = StringUtils.isEmpty(model.branch); - if (emptyUnsubscribeBranch && emptyFromBranch) { - // default branch, remove - toRemove.add(model); - } else if (!emptyUnsubscribeBranch && !emptyFromBranch) { - if (model.branch.equals(branch)) { - // specific branch, remove - toRemove.add(model); - } - } - } - } - } - updateSubscribedStates(); - return true; } public List<FederationModel> refreshFederationRegistrations() throws IOException { diff --git a/src/com/gitblit/client/GitblitManager.java b/src/com/gitblit/client/GitblitManager.java index 8f396f3..d9c2dcc 100644 --- a/src/com/gitblit/client/GitblitManager.java +++ b/src/com/gitblit/client/GitblitManager.java @@ -31,7 +31,6 @@ import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -62,6 +61,7 @@ import com.gitblit.Constants; import com.gitblit.GitBlitException.ForbiddenException; +import com.gitblit.models.FeedModel; import com.gitblit.utils.StringUtils; /** @@ -205,8 +205,8 @@ return; } // preserve feeds - newReg.feeds = reg.feeds; - + newReg.feeds.addAll(reg.feeds); + // use new reg reg = newReg; } @@ -311,7 +311,11 @@ GitblitRegistration reg = new GitblitRegistration(server, url, account, password); String[] feeds = config.getStringList("servers", server, "feeds"); if (feeds != null) { - reg.feeds = new ArrayList<String>(Arrays.asList(feeds)); + // deserialize the field definitions + for (String definition : feeds) { + FeedModel feed = new FeedModel(definition); + reg.feeds.add(feed); + } } reg.lastLogin = lastLogin; registrations.put(reg.name, reg); @@ -343,8 +347,13 @@ if (reg.lastLogin != null) { config.setString("servers", reg.name, "lastLogin", dateFormat.format(reg.lastLogin)); } - if (reg.feeds != null) { - config.setStringList("servers", reg.name, "feeds", reg.feeds); + // serialize the feed definitions + List<String> definitions = new ArrayList<String>(); + for (FeedModel feed : reg.feeds) { + definitions.add(feed.toString()); + } + if (definitions.size() > 0) { + config.setStringList("servers", reg.name, "feeds", definitions); } config.save(); return true; diff --git a/src/com/gitblit/client/GitblitPanel.java b/src/com/gitblit/client/GitblitPanel.java index 10e9c2d..64e85ea 100644 --- a/src/com/gitblit/client/GitblitPanel.java +++ b/src/com/gitblit/client/GitblitPanel.java @@ -56,6 +56,7 @@ import com.gitblit.Constants.RpcRequest; import com.gitblit.client.ClosableTabComponent.CloseTabListener; +import com.gitblit.models.FeedModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.SettingModel; import com.gitblit.models.SyndicatedEntryModel; @@ -127,7 +128,7 @@ tabs = new JTabbedPane(JTabbedPane.BOTTOM); tabs.addTab(Translation.get("gb.repositories"), createRepositoriesPanel()); - tabs.addTab(Translation.get("gb.recentCommits"), createFeedsPanel()); + tabs.addTab(Translation.get("gb.recentActivity"), createFeedsPanel()); tabs.addTab(Translation.get("gb.users"), createUsersPanel()); tabs.addTab(Translation.get("gb.settings"), createSettingsPanel()); tabs.addTab(Translation.get("gb.status"), createStatusPanel()); @@ -186,11 +187,12 @@ subscribeRepository.setEnabled(false); subscribeRepository.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - subscribeRepository(getSelectedRepositories().get(0)); + List<FeedModel> feeds = gitblit.getAvailableFeeds(getSelectedRepositories().get(0)); + subscribeFeeds(feeds); } }); - NameRenderer nameRenderer = new NameRenderer(true); + SubscribedRepositoryRenderer nameRenderer = new SubscribedRepositoryRenderer(gitblit); IndicatorsRenderer typeRenderer = new IndicatorsRenderer(); DefaultTableCellRenderer sizeRenderer = new DefaultTableCellRenderer(); @@ -333,19 +335,34 @@ } }); + JButton subscribeFeeds = new JButton(Translation.get("gb.subscribe") + "..."); + subscribeFeeds.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + subscribeFeeds(gitblit.getAvailableFeeds()); + } + }); + JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); controls.add(refreshFeeds); + controls.add(subscribeFeeds); controls.add(viewCommit); controls.add(viewCommitDiff); controls.add(viewTree); NameRenderer nameRenderer = new NameRenderer(); syndicationModel = new SyndicatedEntryTableModel(); - feedsHeader = new HeaderPanel(Translation.get("gb.recentCommits"), "feed_16x16.png"); + feedsHeader = new HeaderPanel(Translation.get("gb.recentActivity"), "feed_16x16.png"); syndicationEntriesTable = Utils.newTable(syndicationModel, Utils.DATE_FORMAT); String name = syndicationEntriesTable .getColumnName(SyndicatedEntryTableModel.Columns.Author.ordinal()); syndicationEntriesTable.setRowHeight(nameRenderer.getFont().getSize() + 8); + syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer); + name = syndicationEntriesTable.getColumnName(SyndicatedEntryTableModel.Columns.Repository + .ordinal()); + syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer); + + name = syndicationEntriesTable.getColumnName(SyndicatedEntryTableModel.Columns.Branch + .ordinal()); syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer); syndicationEntriesTable.addMouseListener(new MouseAdapter() { @@ -656,7 +673,7 @@ syndicationModel.entries.clear(); syndicationModel.entries.addAll(gitblit.getSyndicatedEntries()); syndicationModel.fireTableDataChanged(); - feedsHeader.setText(Translation.get("gb.recentCommits") + " (" + feedsHeader.setText(Translation.get("gb.recentActivity") + " (" + gitblit.getSyndicatedEntries().size() + ")"); } @@ -921,40 +938,21 @@ } } - protected void subscribeRepository(final RepositoryModel repository) { - if (repository == null) { - return; - } - // TODO this is lame. need better ui. - if (gitblit.isSubscribed(repository, null)) { - // unsubscribe - String msg = MessageFormat.format("Do you want to unsubscribe from {0}?", - repository.name); - String[] options = { "no", "yes" }; - int result = JOptionPane.showOptionDialog(GitblitPanel.this, msg, "Unsubscribe?", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, - options[0]); - if (result == 1) { - if (gitblit.unsubscribe(repository, null)) { - updateFeedsTable(); - updateRepositoriesTable(); - listener.saveRegistration(repository.name, gitblit.reg); - } + protected void subscribeFeeds(final List<FeedModel> feeds) { + SubscriptionsDialog dialog = new SubscriptionsDialog(feeds) { + + private static final long serialVersionUID = 1L; + + @Override + public void save() { + gitblit.updateSubscribedFeeds(feeds); + listener.saveRegistration(gitblit.reg.name, gitblit.reg); + setVisible(false); + updateRepositoriesTable(); } - } else { - // subscribe - String msg = MessageFormat.format("Do you want to subscribe to {0}?", repository.name); - String[] options = { "no", "yes" }; - int result = JOptionPane.showOptionDialog(GitblitPanel.this, msg, "Subscribe?", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, - options[0]); - if (result == 1) { - if (gitblit.subscribe(repository, null)) { - updateRepositoriesTable(); - listener.saveRegistration(repository.name, gitblit.reg); - } - } - } + }; + dialog.setLocationRelativeTo(GitblitPanel.this); + dialog.setVisible(true); } protected void refreshFeeds() { diff --git a/src/com/gitblit/client/GitblitRegistration.java b/src/com/gitblit/client/GitblitRegistration.java index cbd4324..05b23d0 100644 --- a/src/com/gitblit/client/GitblitRegistration.java +++ b/src/com/gitblit/client/GitblitRegistration.java @@ -16,9 +16,11 @@ package com.gitblit.client; import java.io.Serializable; +import java.util.ArrayList; import java.util.Date; import java.util.List; +import com.gitblit.models.FeedModel; import com.gitblit.utils.StringUtils; /** @@ -37,7 +39,7 @@ char[] password; boolean savePassword; Date lastLogin; - List<String> feeds; + final List<FeedModel> feeds; public GitblitRegistration(String name, String url, String account, char[] password) { this.url = url; @@ -49,6 +51,24 @@ } else { this.name = name; } + feeds = new ArrayList<FeedModel>(); + } + + public void updateSubscribedFeeds(List<FeedModel> list) { + for (FeedModel feed : list) { + if (feeds.contains(feed)) { + // possibly unsubscribe/remove feed + int index = feeds.indexOf(feed); + FeedModel existingFeed = feeds.get(index); + existingFeed.subscribed = feed.subscribed; + if (!existingFeed.subscribed) { + feeds.remove(index); + } + } else if (feed.subscribed) { + // new subscription + feeds.add(feed); + } + } } @Override diff --git a/src/com/gitblit/client/NameRenderer.java b/src/com/gitblit/client/NameRenderer.java index ce04255..f334d42 100644 --- a/src/com/gitblit/client/NameRenderer.java +++ b/src/com/gitblit/client/NameRenderer.java @@ -18,11 +18,8 @@ import java.awt.Color; import java.awt.Component; -import javax.swing.ImageIcon; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; - -import com.gitblit.models.RepositoryModel; /** * Repository name cell renderer. This renderer shows the group name in a gray @@ -35,26 +32,13 @@ private static final long serialVersionUID = 1L; - final String groupSpan; - - private final boolean displayIcon; - - private final ImageIcon blankIcon; - - private final ImageIcon subscribedIcon; + private final String groupSpan; public NameRenderer() { - this(false); + this(Color.gray, new Color(0x00, 0x69, 0xD6)); } - public NameRenderer(boolean showIcon) { - this(Color.gray, new Color(0x00, 0x69, 0xD6), showIcon); - } - - private NameRenderer(Color group, Color repo, boolean showIcon) { - blankIcon = new ImageIcon(getClass().getResource("/blank.png")); - subscribedIcon = new ImageIcon(getClass().getResource("/bullet_feed.png")); - displayIcon = showIcon; + private NameRenderer(Color group, Color repo) { groupSpan = "<span style='color:" + getHexColor(group) + "'>"; setForeground(repo); } @@ -71,26 +55,14 @@ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (value instanceof RepositoryModel) { - RepositoryModel model = (RepositoryModel) value; - String name = value.toString(); - int lastSlash = name.lastIndexOf('/'); - if (!isSelected && lastSlash > -1) { - String group = name.substring(0, lastSlash + 1); - String repo = name.substring(lastSlash + 1); - setText("<html><body>" + groupSpan + group + "</span>" + repo); - } else { - this.setText(name); - } - if (displayIcon) { - if (model.subscribed) { - setIcon(subscribedIcon); - } else { - setIcon(blankIcon); - } - } + String name = value.toString(); + int lastSlash = name.lastIndexOf('/'); + if (!isSelected && lastSlash > -1) { + String group = name.substring(0, lastSlash + 1); + String repo = name.substring(lastSlash + 1); + setText("<html><body>" + groupSpan + group + "</span>" + repo); } else { - this.setText(value.toString()); + this.setText(name); } return this; } diff --git a/src/com/gitblit/client/SubscribedRepositoryRenderer.java b/src/com/gitblit/client/SubscribedRepositoryRenderer.java new file mode 100644 index 0000000..9943333 --- /dev/null +++ b/src/com/gitblit/client/SubscribedRepositoryRenderer.java @@ -0,0 +1,62 @@ +/* + * 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.Component; + +import javax.swing.ImageIcon; +import javax.swing.JTable; + +import com.gitblit.models.RepositoryModel; + +/** + * Displays a subscribed icon on the left of the repository name, if there is at + * least one subscribed branch. + * + * @author James Moger + * + */ +public class SubscribedRepositoryRenderer extends NameRenderer { + + private static final long serialVersionUID = 1L; + + private final GitblitClient gitblit; + + private final ImageIcon blankIcon; + + private final ImageIcon subscribedIcon; + + public SubscribedRepositoryRenderer(GitblitClient gitblit) { + super(); + this.gitblit = gitblit; + blankIcon = new ImageIcon(getClass().getResource("/blank.png")); + subscribedIcon = new ImageIcon(getClass().getResource("/bullet_feed.png")); + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, + boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (value instanceof RepositoryModel) { + RepositoryModel model = (RepositoryModel) value; + if (gitblit.isSubscribed(model)) { + setIcon(subscribedIcon); + } else { + setIcon(blankIcon); + } + } + return this; + } +} diff --git a/src/com/gitblit/client/SubscriptionsDialog.java b/src/com/gitblit/client/SubscriptionsDialog.java new file mode 100644 index 0000000..64a88d9 --- /dev/null +++ b/src/com/gitblit/client/SubscriptionsDialog.java @@ -0,0 +1,159 @@ +/* + * 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.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.util.List; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.KeyStroke; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import com.gitblit.models.FeedModel; + +/** + * Displays a list of repository branches and allows the user to check or + * uncheck branches. + * + * @author James Moger + * + */ +public abstract class SubscriptionsDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private final List<FeedModel> feeds; + + private JTable feedsTable; + + private FeedsTableModel model; + + public SubscriptionsDialog(List<FeedModel> registrations) { + super(); + this.feeds = registrations; + setTitle(Translation.get("gb.manage")); + setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage()); + initialize(); + setSize(600, 400); + } + + @Override + protected JRootPane createRootPane() { + KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); + JRootPane rootPane = new JRootPane(); + rootPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + setVisible(false); + } + }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); + return rootPane; + } + + private void initialize() { + NameRenderer nameRenderer = new NameRenderer(); + model = new FeedsTableModel(feeds); + feedsTable = Utils.newTable(model, Utils.DATE_FORMAT); + feedsTable.setRowHeight(nameRenderer.getFont().getSize() + 8); + feedsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + int viewRow = feedsTable.getSelectedRow(); + if (viewRow == -1) { + return; + } + int modelRow = feedsTable.convertRowIndexToModel(viewRow); + FeedModel feed = model.get(modelRow); + feed.subscribed = !feed.subscribed; + model.fireTableDataChanged(); + } + }); + + String repository = feedsTable.getColumnName(FeedsTableModel.Columns.Repository.ordinal()); + feedsTable.getColumn(repository).setCellRenderer(nameRenderer); + + String branch = feedsTable.getColumnName(FeedsTableModel.Columns.Branch.ordinal()); + feedsTable.getColumn(branch).setCellRenderer(nameRenderer); + + String subscribed = feedsTable.getColumnName(FeedsTableModel.Columns.Subscribed.ordinal()); + feedsTable.getColumn(subscribed).setCellRenderer(new BooleanCellRenderer()); + feedsTable.getColumn(subscribed).setMinWidth(30); + feedsTable.getColumn(subscribed).setMaxWidth(30); + + Utils.packColumns(feedsTable, 5); + + final JButton cancel = new JButton(Translation.get("gb.cancel")); + cancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + setVisible(false); + } + }); + + final JButton save = new JButton(Translation.get("gb.save")); + save.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + save(); + } + }); + + feedsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + } + }); + + JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); + controls.add(cancel); + controls.add(save); + + final Insets insets = new Insets(5, 5, 5, 5); + JPanel centerPanel = new JPanel(new BorderLayout(5, 5)) { + + private static final long serialVersionUID = 1L; + + public Insets getInsets() { + return insets; + } + }; + centerPanel.add(new HeaderPanel(Translation.get("gb.subscribe") + "...", "feed_16x16.png"), + BorderLayout.NORTH); + centerPanel.add(new JScrollPane(feedsTable), BorderLayout.CENTER); + centerPanel.add(controls, BorderLayout.SOUTH); + + getContentPane().setLayout(new BorderLayout(5, 5)); + getContentPane().add(centerPanel, BorderLayout.CENTER); + } + + public abstract void save(); +} diff --git a/src/com/gitblit/client/SyndicatedEntryTableModel.java b/src/com/gitblit/client/SyndicatedEntryTableModel.java index 4f25c9b..db62b1a 100644 --- a/src/com/gitblit/client/SyndicatedEntryTableModel.java +++ b/src/com/gitblit/client/SyndicatedEntryTableModel.java @@ -25,7 +25,7 @@ import com.gitblit.models.SyndicatedEntryModel; /** - * Table model of List<SyndicatedEntryModel> + * Table model for a list of retrieved feed entries. * * @author James Moger * @@ -37,7 +37,7 @@ List<SyndicatedEntryModel> entries; enum Columns { - Date, Repository, Author, Message; + Date, Repository, Branch, Author, Message; @Override public String toString() { @@ -76,6 +76,8 @@ return Translation.get("gb.date"); case Repository: return Translation.get("gb.repository"); + case Branch: + return Translation.get("gb.branch"); case Author: return Translation.get("gb.author"); case Message: @@ -107,6 +109,8 @@ return entry.published; case Repository: return entry.repository; + case Branch: + return entry.branch; case Author: return entry.author; case Message: diff --git a/src/com/gitblit/client/Translation.java b/src/com/gitblit/client/Translation.java index cd5515b..2e7b5bb 100644 --- a/src/com/gitblit/client/Translation.java +++ b/src/com/gitblit/client/Translation.java @@ -15,42 +15,34 @@ */ package com.gitblit.client; -import java.io.InputStream; -import java.util.Properties; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +/** + * Loads the Gitblit language resource file. + * + * @author James Moger + * + */ public class Translation { - private final static Properties translation; + private final static ResourceBundle translation; static { - translation = new Properties(); - InputStream is = null; + ResourceBundle bundle; try { - is = Translation.class.getResource("/com/gitblit/wicket/GitBlitWebApp.properties") - .openStream(); - } catch (Throwable t) { - try { - is = Translation.class.getResource("/GitBlitWebApp.properties").openStream(); - } catch (Throwable x) { - } + // development location + bundle = ResourceBundle.getBundle("com/gitblit/wicket/GitBlitWebApp"); + } catch (MissingResourceException e) { + // runtime location + bundle = ResourceBundle.getBundle("GitBlitWebApp"); } - if (is != null) { - try { - translation.load(is); - } catch (Throwable t) { - - } finally { - try { - is.close(); - } catch (Throwable t) { - } - } - } + translation = bundle; } public static String get(String key) { if (translation.containsKey(key)) { - return translation.getProperty(key).trim(); + return translation.getString(key).trim(); } return key; } diff --git a/src/com/gitblit/models/FeedModel.java b/src/com/gitblit/models/FeedModel.java new file mode 100644 index 0000000..67cff95 --- /dev/null +++ b/src/com/gitblit/models/FeedModel.java @@ -0,0 +1,96 @@ +/* + * 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.models; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.gitblit.utils.StringUtils; + +/** + * FeedModel represents a syndication (RSS) feed. + * + * @author James Moger + */ +public class FeedModel implements Serializable, Comparable<FeedModel> { + + public String repository; + public String branch; + public int maxRetrieval; + public Date lastRefresh; + + public boolean subscribed; + + private static final long serialVersionUID = 1L; + + public FeedModel() { + this(""); + } + + public FeedModel(String definition) { + maxRetrieval = -1; + lastRefresh = new Date(0); + + String[] fields = definition.split(":"); + repository = fields[0]; + if (fields.length > 1) { + branch = fields[1]; + maxRetrieval = Integer.parseInt(fields[2]); + try { + lastRefresh = new SimpleDateFormat("yyyyMMddHHmmss").parse(fields[3]); + } catch (ParseException e) { + } + subscribed = true; + } + } + + @Override + public String toString() { + return MessageFormat.format("{0}:{1}:{2,number,0}:{3,date,yyyyMMddHHmmss}", repository, + branch, maxRetrieval, lastRefresh); + } + + @Override + public int compareTo(FeedModel o) { + int repositoryCompare = repository.compareTo(o.repository); + if (repositoryCompare == 0) { + // same repository + if (StringUtils.isEmpty(branch)) { + return 1; + } else if (StringUtils.isEmpty(o.branch)) { + return -1; + } + return branch.compareTo(o.branch); + } + return repositoryCompare; + } + + @Override + public int hashCode() { + return (repository + (StringUtils.isEmpty(branch) ? "" : branch)).toLowerCase().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof FeedModel) { + return hashCode() == o.hashCode(); + } + return false; + } +} diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java index af42061..9a774fb 100644 --- a/src/com/gitblit/models/RepositoryModel.java +++ b/src/com/gitblit/models/RepositoryModel.java @@ -55,7 +55,6 @@ public String frequency; public String origin; public String size; - public boolean subscribed; public RepositoryModel() { this("", "", "", new Date(0)); diff --git a/src/com/gitblit/utils/RpcUtils.java b/src/com/gitblit/utils/RpcUtils.java index faa910b..c2f20d8 100644 --- a/src/com/gitblit/utils/RpcUtils.java +++ b/src/com/gitblit/utils/RpcUtils.java @@ -27,6 +27,7 @@ import com.gitblit.models.FederationModel; import com.gitblit.models.FederationProposal; import com.gitblit.models.FederationSet; +import com.gitblit.models.FeedModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; @@ -389,7 +390,7 @@ } /** - * Retrieves a map of all branches in the Gitblit server keyed by + * Retrieves a map of local branches in the Gitblit server keyed by * repository. * * @param serverUrl @@ -398,12 +399,36 @@ * @return * @throws IOException */ - public static Map<String, Collection<String>> getAllBranches(String serverUrl, - String account, char[] password) throws IOException { + public static Map<String, Collection<String>> getBranches(String serverUrl, String account, + char[] password) throws IOException { String url = asLink(serverUrl, RpcRequest.LIST_BRANCHES); - Map<String, Collection<String>> allReferences = JsonUtils.retrieveJson(url, - BRANCHES_TYPE, account, password); - return allReferences; + Map<String, Collection<String>> branches = JsonUtils.retrieveJson(url, BRANCHES_TYPE, + account, password); + return branches; + } + + /** + * Retrieves a list of available branch feeds in the Gitblit server. + * + * @param serverUrl + * @param account + * @param password + * @return + * @throws IOException + */ + public static List<FeedModel> getBranchFeeds(String serverUrl, String account, char[] password) + throws IOException { + List<FeedModel> feeds = new ArrayList<FeedModel>(); + Map<String, Collection<String>> allBranches = getBranches(serverUrl, account, password); + for (Map.Entry<String, Collection<String>> entry : allBranches.entrySet()) { + for (String branch : entry.getValue()) { + FeedModel feed = new FeedModel(); + feed.repository = entry.getKey(); + feed.branch = branch; + feeds.add(feed); + } + } + return feeds; } /** diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index e16b44d..6d20a72 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -177,5 +177,6 @@ gb.version = version gb.releaseDate = release date gb.date = date -gb.recentCommits = recent commits -gb.subscribe = subscribe \ No newline at end of file +gb.recentActivity = recent activity +gb.subscribe = subscribe +gb.branch = branch \ No newline at end of file diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java index 637d488..37a4955 100644 --- a/tests/com/gitblit/tests/RpcTests.java +++ b/tests/com/gitblit/tests/RpcTests.java @@ -244,7 +244,7 @@ } public void testBranches() throws Exception { - Map<String, Collection<String>> branches = RpcUtils.getAllBranches(url, account, + Map<String, Collection<String>> branches = RpcUtils.getBranches(url, account, password.toCharArray()); assertTrue(branches != null); assertTrue(branches.size() > 0); -- Gitblit v1.9.1