Kensuke Matsuzaki
2013-04-15 ed566a162c780faa0d6c84fac8fbbd3738586445
commit | author | age
9119cf 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit.client;
17
18 import java.awt.BorderLayout;
c7a721 19 import java.awt.Cursor;
9119cf 20 import java.awt.FlowLayout;
JM 21 import java.awt.Insets;
e33b91 22 import java.awt.Rectangle;
9119cf 23 import java.awt.event.ActionEvent;
JM 24 import java.awt.event.ActionListener;
25 import java.awt.event.MouseAdapter;
26 import java.awt.event.MouseEvent;
27 import java.awt.event.WindowAdapter;
28 import java.awt.event.WindowEvent;
29 import java.io.IOException;
30 import java.util.List;
31
32 import javax.swing.DefaultComboBoxModel;
33 import javax.swing.ImageIcon;
34 import javax.swing.JButton;
35 import javax.swing.JComboBox;
36 import javax.swing.JFrame;
37 import javax.swing.JLabel;
38 import javax.swing.JPanel;
39 import javax.swing.JScrollPane;
40 import javax.swing.JTable;
41 import javax.swing.JTextField;
42 import javax.swing.SwingWorker;
43 import javax.swing.event.ListSelectionEvent;
44 import javax.swing.event.ListSelectionListener;
45
46 import com.gitblit.Constants;
ee458f 47 import com.gitblit.models.FeedEntryModel;
e493cf 48 import com.gitblit.models.RepositoryModel;
9119cf 49 import com.gitblit.utils.StringUtils;
JM 50
51 /**
52  * The search dialog allows searching of a repository branch. This matches the
53  * search implementation of the site.
54  * 
55  * @author James Moger
56  * 
57  */
58 public class SearchDialog extends JFrame {
59
60     private static final long serialVersionUID = 1L;
61
ee458f 62     private final boolean isSearch;
JM 63
9119cf 64     private final GitblitClient gitblit;
JM 65
ee458f 66     private FeedEntryTableModel tableModel;
9119cf 67
JM 68     private HeaderPanel header;
69
70     private JTable table;
71
72     private JComboBox repositorySelector;
73
74     private DefaultComboBoxModel branchChoices;
75
76     private JComboBox branchSelector;
77
78     private JComboBox searchTypeSelector;
79
80     private JTextField searchFragment;
81
82     private JComboBox maxHitsSelector;
83
e33b91 84     private int page;
JM 85
86     private JButton prev;
87
88     private JButton next;
89
ee458f 90     public SearchDialog(GitblitClient gitblit, boolean isSearch) {
9119cf 91         super();
JM 92         this.gitblit = gitblit;
ee458f 93         this.isSearch = isSearch;
JM 94         setTitle(Translation.get(isSearch ? "gb.search" : "gb.log"));
c7e7e9 95         setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage());
9119cf 96         initialize();
ee458f 97         setSize(900, 550);
9119cf 98     }
JM 99
100     private void initialize() {
101
e33b91 102         prev = new JButton("<");
JM 103         prev.setToolTipText(Translation.get("gb.pagePrevious"));
104         prev.setEnabled(false);
105         prev.addActionListener(new ActionListener() {
106             public void actionPerformed(ActionEvent e) {
107                 search(--page);
108             }
109         });
110
111         next = new JButton(">");
112         next.setToolTipText(Translation.get("gb.pageNext"));
113         next.setEnabled(false);
114         next.addActionListener(new ActionListener() {
115             public void actionPerformed(ActionEvent e) {
116                 search(++page);
117             }
118         });
119
ee458f 120         final JButton search = new JButton(Translation.get(isSearch ? "gb.search" : "gb.refresh"));
9119cf 121         search.addActionListener(new ActionListener() {
JM 122             public void actionPerformed(ActionEvent e) {
e33b91 123                 search(0);
9119cf 124             }
JM 125         });
126
127         final JButton viewCommit = new JButton(Translation.get("gb.view"));
128         viewCommit.setEnabled(false);
129         viewCommit.addActionListener(new ActionListener() {
130             public void actionPerformed(ActionEvent e) {
131                 viewCommit();
132             }
133         });
134
135         final JButton viewCommitDiff = new JButton(Translation.get("gb.commitdiff"));
136         viewCommitDiff.setEnabled(false);
137         viewCommitDiff.addActionListener(new ActionListener() {
138             public void actionPerformed(ActionEvent e) {
139                 viewCommitDiff();
140             }
141         });
142
143         final JButton viewTree = new JButton(Translation.get("gb.tree"));
144         viewTree.setEnabled(false);
145         viewTree.addActionListener(new ActionListener() {
146             public void actionPerformed(ActionEvent e) {
147                 viewTree();
148             }
149         });
150
151         JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, Utils.MARGIN, 0));
152         controls.add(viewCommit);
153         controls.add(viewCommitDiff);
154         controls.add(viewTree);
155
156         NameRenderer nameRenderer = new NameRenderer();
ee458f 157         tableModel = new FeedEntryTableModel();
JM 158         header = new HeaderPanel(Translation.get(isSearch ? "gb.search" : "gb.log"),
159                 isSearch ? "search-icon.png" : "commit_changes_16x16.png");
9119cf 160         table = Utils.newTable(tableModel, Utils.DATE_FORMAT);
JM 161
ee458f 162         String name = table.getColumnName(FeedEntryTableModel.Columns.Author.ordinal());
9119cf 163         table.getColumn(name).setCellRenderer(nameRenderer);
ee458f 164         name = table.getColumnName(FeedEntryTableModel.Columns.Repository.ordinal());
9119cf 165         table.getColumn(name).setCellRenderer(nameRenderer);
JM 166
ee458f 167         name = table.getColumnName(FeedEntryTableModel.Columns.Branch.ordinal());
9119cf 168         table.getColumn(name).setCellRenderer(new BranchRenderer());
JM 169
ee458f 170         name = table.getColumnName(FeedEntryTableModel.Columns.Message.ordinal());
9119cf 171         table.getColumn(name).setCellRenderer(new MessageRenderer());
JM 172
173         table.addMouseListener(new MouseAdapter() {
174             public void mouseClicked(MouseEvent e) {
175                 if (e.getClickCount() == 2) {
176                     if (e.isControlDown()) {
177                         viewCommitDiff();
178                     } else {
179                         viewCommit();
180                     }
181                 }
182             }
183         });
184
185         table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
186             @Override
187             public void valueChanged(ListSelectionEvent e) {
188                 if (e.getValueIsAdjusting()) {
189                     return;
190                 }
191                 boolean singleSelection = table.getSelectedRowCount() == 1;
192                 viewCommit.setEnabled(singleSelection);
193                 viewCommitDiff.setEnabled(singleSelection);
194                 viewTree.setEnabled(singleSelection);
195             }
196         });
197
198         repositorySelector = new JComboBox(gitblit.getRepositories().toArray());
199         repositorySelector.setRenderer(nameRenderer);
200         repositorySelector.setForeground(nameRenderer.getForeground());
201         repositorySelector.addActionListener(new ActionListener() {
202             public void actionPerformed(ActionEvent event) {
203                 // repopulate the branch list based on repository selection
204                 // preserve branch selection, if possible
205                 String selectedBranch = null;
206                 if (branchSelector.getSelectedIndex() > -1) {
207                     selectedBranch = branchSelector.getSelectedItem().toString();
208                 }
209                 updateBranches();
41cffb 210                 if (StringUtils.isEmpty(selectedBranch)) {
JM 211                     // do not select branch
212                     branchSelector.setSelectedIndex(-1);
213                 } else {
9119cf 214                     if (branchChoices.getIndexOf(selectedBranch) > -1) {
41cffb 215                         // select branch
9119cf 216                         branchChoices.setSelectedItem(selectedBranch);
41cffb 217                     } else {
JM 218                         // branch does not exist, do not select branch
219                         branchSelector.setSelectedIndex(-1);
9119cf 220                     }
JM 221                 }
222             }
223         });
224
225         branchChoices = new DefaultComboBoxModel();
226         branchSelector = new JComboBox(branchChoices);
ee458f 227         branchSelector.setRenderer(new BranchRenderer());
9119cf 228
JM 229         searchTypeSelector = new JComboBox(Constants.SearchType.values());
230         searchTypeSelector.setSelectedItem(Constants.SearchType.COMMIT);
231
232         maxHitsSelector = new JComboBox(new Integer[] { 25, 50, 75, 100 });
e33b91 233         maxHitsSelector.setSelectedIndex(0);
9119cf 234
JM 235         searchFragment = new JTextField(25);
236         searchFragment.addActionListener(new ActionListener() {
237             public void actionPerformed(ActionEvent event) {
e33b91 238                 search(0);
9119cf 239             }
JM 240         });
241
41cffb 242         JPanel queryPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, Utils.MARGIN, 0));
JM 243         queryPanel.add(new JLabel(Translation.get("gb.repository")));
244         queryPanel.add(repositorySelector);
245         queryPanel.add(new JLabel(Translation.get("gb.branch")));
246         queryPanel.add(branchSelector);
ee458f 247         if (isSearch) {
JM 248             queryPanel.add(new JLabel(Translation.get("gb.type")));
249             queryPanel.add(searchTypeSelector);
250         }
41cffb 251         queryPanel.add(new JLabel(Translation.get("gb.maxHits")));
JM 252         queryPanel.add(maxHitsSelector);
253
254         JPanel actionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, Utils.MARGIN, 0));
255         actionsPanel.add(search);
256         actionsPanel.add(prev);
257         actionsPanel.add(next);
258
259         JPanel northControls = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN));
260         northControls.add(queryPanel, BorderLayout.WEST);
ee458f 261         if (isSearch) {
JM 262             northControls.add(searchFragment, BorderLayout.CENTER);
263         }
41cffb 264         northControls.add(actionsPanel, BorderLayout.EAST);
9119cf 265
JM 266         JPanel northPanel = new JPanel(new BorderLayout(0, Utils.MARGIN));
267         northPanel.add(header, BorderLayout.NORTH);
268         northPanel.add(northControls, BorderLayout.CENTER);
269
270         JPanel contentPanel = new JPanel() {
271
272             private static final long serialVersionUID = 1L;
273
274             @Override
275             public Insets getInsets() {
276                 return Utils.INSETS;
277             }
278         };
279         contentPanel.setLayout(new BorderLayout(Utils.MARGIN, Utils.MARGIN));
280         contentPanel.add(northPanel, BorderLayout.NORTH);
281         contentPanel.add(new JScrollPane(table), BorderLayout.CENTER);
282         contentPanel.add(controls, BorderLayout.SOUTH);
283         setLayout(new BorderLayout());
284         add(contentPanel, BorderLayout.CENTER);
a568f2 285         addWindowListener(new WindowAdapter() {
JM 286             @Override
287             public void windowOpened(WindowEvent event) {
288                 if (isSearch) {
ee458f 289                     searchFragment.requestFocus();
a568f2 290                 } else {
JM 291                     search(0);
ee458f 292                 }
a568f2 293             }
9119cf 294
a568f2 295             @Override
JM 296             public void windowActivated(WindowEvent event) {
297                 if (isSearch) {
ee458f 298                     searchFragment.requestFocus();
JM 299                 }
a568f2 300             }
JM 301         });
9119cf 302     }
JM 303
304     public void selectRepository(RepositoryModel repository) {
305         repositorySelector.setSelectedItem(repository);
306     }
307
308     private void updateBranches() {
309         String repository = null;
310         if (repositorySelector.getSelectedIndex() > -1) {
311             repository = repositorySelector.getSelectedItem().toString();
312         }
313         List<String> branches = gitblit.getBranches(repository);
314         branchChoices.removeAllElements();
315         for (String branch : branches) {
316             branchChoices.addElement(branch);
317         }
318     }
319
e33b91 320     protected void search(final int page) {
JM 321         this.page = page;
9119cf 322         final String repository = repositorySelector.getSelectedItem().toString();
JM 323         final String branch = branchSelector.getSelectedIndex() > -1 ? branchSelector
324                 .getSelectedItem().toString() : null;
325         final Constants.SearchType searchType = (Constants.SearchType) searchTypeSelector
326                 .getSelectedItem();
ee458f 327         final String fragment = isSearch ? searchFragment.getText() : null;
9119cf 328         final int maxEntryCount = maxHitsSelector.getSelectedIndex() > -1 ? ((Integer) maxHitsSelector
JM 329                 .getSelectedItem()) : -1;
e33b91 330
ee458f 331         if (isSearch && StringUtils.isEmpty(fragment)) {
9119cf 332             return;
JM 333         }
c7a721 334         setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
ee458f 335         SwingWorker<List<FeedEntryModel>, Void> worker = new SwingWorker<List<FeedEntryModel>, Void>() {
9119cf 336             @Override
ee458f 337             protected List<FeedEntryModel> doInBackground() throws IOException {
JM 338                 if (isSearch) {
339                     return gitblit.search(repository, branch, fragment, searchType, maxEntryCount,
340                             page);
341                 } else {
342                     return gitblit.log(repository, branch, maxEntryCount, page);
343                 }
9119cf 344             }
JM 345
346             @Override
347             protected void done() {
c7a721 348                 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
9119cf 349                 try {
ee458f 350                     List<FeedEntryModel> results = get();
JM 351                     if (isSearch) {
352                         updateTable(true, fragment, results);
353                     } else {
354                         updateTable(true, branch == null ? "" : branch, results);
355                     }
9119cf 356                 } catch (Throwable t) {
JM 357                     Utils.showException(SearchDialog.this, t);
358                 }
359             }
360         };
361         worker.execute();
362     }
363
ee458f 364     protected void updateTable(boolean pack, String text, List<FeedEntryModel> entries) {
9119cf 365         tableModel.entries.clear();
JM 366         tableModel.entries.addAll(entries);
367         tableModel.fireTableDataChanged();
a568f2 368         setTitle(Translation.get(isSearch ? "gb.search" : "gb.log")
JM 369                 + (StringUtils.isEmpty(text) ? "" : (": " + text)) + " (" + entries.size()
370                 + (page > 0 ? (", pg " + (page + 1)) : "") + ")");
9119cf 371         header.setText(getTitle());
JM 372         if (pack) {
373             Utils.packColumns(table, Utils.MARGIN);
374         }
e33b91 375         table.scrollRectToVisible(new Rectangle(table.getCellRect(0, 0, true)));
JM 376
377         // update pagination buttons
378         int maxHits = (Integer) maxHitsSelector.getSelectedItem();
379         next.setEnabled(entries.size() == maxHits);
380         prev.setEnabled(page > 0);
9119cf 381     }
JM 382
ee458f 383     protected FeedEntryModel getSelectedSyndicatedEntry() {
9119cf 384         int viewRow = table.getSelectedRow();
JM 385         int modelRow = table.convertRowIndexToModel(viewRow);
ee458f 386         FeedEntryModel entry = tableModel.get(modelRow);
9119cf 387         return entry;
JM 388     }
389
390     protected void viewCommit() {
ee458f 391         FeedEntryModel entry = getSelectedSyndicatedEntry();
9119cf 392         Utils.browse(entry.link);
JM 393     }
394
395     protected void viewCommitDiff() {
ee458f 396         FeedEntryModel entry = getSelectedSyndicatedEntry();
9119cf 397         Utils.browse(entry.link.replace("/commit/", "/commitdiff/"));
JM 398     }
399
400     protected void viewTree() {
ee458f 401         FeedEntryModel entry = getSelectedSyndicatedEntry();
9119cf 402         Utils.browse(entry.link.replace("/commit/", "/tree/"));
JM 403     }
404 }