diff -r df2f526ba7ed bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/DefaultRepositorySelector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/DefaultRepositorySelector.java Fri May 29 21:51:39 2009 +0200 @@ -0,0 +1,167 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.bugtracking.vcs; + +import java.awt.EventQueue; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.io.File; +import java.util.logging.Logger; +import org.netbeans.modules.bugtracking.spi.Repository; +import org.netbeans.modules.bugtracking.util.BugtrackingOwnerSupport; +import org.openide.util.Exceptions; +import org.openide.util.RequestProcessor; +import static java.util.logging.Level.FINEST; + +/** + * Determines the default issue tracking repository for the + * {@code HookPanel} and selects it in the panel's combo-box. + * It is activated by method {@code hierarchyChanged} when the hook panel + * is displayed. At this moment, a routine for finding the default + * repository is started in a separated thread. Once the routine finishes, + * the determined default repository is selected in the repository + * combo-box in the {@code HookPanel}, unless the user has already selected + * one. + * + * @author Marian Petras + */ +final class DefaultRepositorySelector implements HierarchyListener, Runnable { + + private static final Logger LOG + = Logger.getLogger(DefaultRepositorySelector.class.getName()); + + private final HookPanel hookPanel; + private final File refFile; + private boolean tooLate; + private transient Repository defaultRepo; + + static void setup(HookPanel hookPanel, File referenceFile) { + hookPanel.addHierarchyListener( + new DefaultRepositorySelector(hookPanel, referenceFile)); + } + + private DefaultRepositorySelector(HookPanel hookPanel, File refFile) { + super(); + this.hookPanel = hookPanel; + this.refFile = refFile; + } + + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) { + assert e.getChanged() == hookPanel; + if (hookPanel.isDisplayable()) { + hookPanelDisplayed(); + } else { + hookPanelClosed(); + } + } + } + + private void hookPanelDisplayed() { + RequestProcessor.getDefault().post(this); + } + + private void hookPanelClosed() { + /* + * The panel had been closed sooner than the default repository has been + * determined. + */ + tooLate = true; + hookPanel.removeHierarchyListener(this); + } + + public void run() { + if (RequestProcessor.getDefault().isRequestProcessorThread()) { + findDefaultRepository(); + } else { + assert EventQueue.isDispatchThread(); + + LOG.finest("run() called from AWT - going to select the repository"); //NOI18N + + if (tooLate) { + LOG.finest(" - too late - the HookPanel has been already closed"); //NOI18N + return; + } + + hookPanel.removeHierarchyListener(this); + + if (defaultRepo == null) { + LOG.finest(" - default repository not determined - abort"); //NOI18N + return; + } + + hookPanel.preselectRepository(defaultRepo); + } + } + + private void findDefaultRepository() { + assert RequestProcessor.getDefault().isRequestProcessorThread(); + long startTimeMillis, endTimeMillis; + Repository result; + + startTimeMillis = System.currentTimeMillis(); + if (refFile != null) { + result = BugtrackingOwnerSupport.getInstance() + .getRepository(refFile, false); + if ((result == null) && LOG.isLoggable(FINEST)) { + LOG.finest(" could not find issue tracker for " + refFile); //NOI18N + } + } else { + result = BugtrackingOwnerSupport.getInstance() + .getRepository(BugtrackingOwnerSupport.ContextType.ALL_PROJECTS); + } + endTimeMillis = System.currentTimeMillis(); + + if (LOG.isLoggable(FINEST)) { + LOG.finest("BugtrackingOwnerSupport.getRepository(...) took " //NOI18N + + (endTimeMillis - startTimeMillis) + " ms."); //NOI18N + } + + if (result != null) { + if (LOG.isLoggable(FINEST)) { + LOG.finest(" - default repository: " + result.getDisplayName()); //NOI18N + } + defaultRepo = result; + EventQueue.invokeLater(this); + } else { + LOG.finest(" - default repository: "); //NOI18N + } + } +} diff -r df2f526ba7ed bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HgHookImpl.java --- a/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HgHookImpl.java Fri May 29 12:27:03 2009 +0200 +++ b/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HgHookImpl.java Fri May 29 21:51:39 2009 +0200 @@ -233,21 +233,15 @@ @Override public JPanel createComponent(HgHookContext context) { - Repository[] repos = BugtrackingUtil.getKnownRepositories(); + File referenceFile; if(context.getFiles().length == 0) { + referenceFile = null; LOG.warning("creating hg hook component for zero files"); // NOI18N - Repository repoToSelect - = BugtrackingOwnerSupport.getInstance() - .getRepository(BugtrackingOwnerSupport.ContextType.ALL_PROJECTS); - panel = new HookPanel(repos, repoToSelect); } else { - File file = context.getFiles()[0]; - Repository repoToSelect = BugtrackingOwnerSupport.getInstance().getRepository(file, false); - if(repoToSelect == null) { - LOG.log(Level.FINE, " could not find issue tracker for " + file); // NOI18N - } - panel = new HookPanel(repos, repoToSelect); + referenceFile = context.getFiles()[0]; } + panel = new HookPanel(getKnownRepositories()); + DefaultRepositorySelector.setup(panel, referenceFile); panel.changeRevisionFormatButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onShowRevisionFormat(); @@ -261,6 +255,18 @@ return panel; } + private static Repository[] getKnownRepositories() { + Repository[] repos; + long startTimeMillis = System.currentTimeMillis(); + repos = BugtrackingUtil.getKnownRepositories(); + long endTimeMillis = System.currentTimeMillis(); + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("BugtrackingUtil.getKnownRepositories() took " //NOI18N + + (endTimeMillis - startTimeMillis) + " ms."); //NOI18N + } + return repos; + } + @Override public String getDisplayName() { return name; diff -r df2f526ba7ed bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HookPanel.java --- a/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HookPanel.java Fri May 29 12:27:03 2009 +0200 +++ b/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/HookPanel.java Fri May 29 21:51:39 2009 +0200 @@ -48,25 +48,33 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.logging.Logger; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JList; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; import org.netbeans.modules.bugtracking.ui.search.QuickSearchComboBar; import org.netbeans.modules.bugtracking.spi.Issue; import org.netbeans.modules.bugtracking.spi.Repository; import org.netbeans.modules.bugtracking.util.BugtrackingUtil; import org.netbeans.modules.versioning.util.VerticallyNonResizingPanel; +import static java.util.logging.Level.FINER; /** * * @author Tomas Stupka */ public class HookPanel extends VerticallyNonResizingPanel implements ItemListener, PropertyChangeListener { + + private static Logger LOG = Logger.getLogger("org.netbeans.modules.bugtracking.vcshooks.HookPanel"); // NOI18N + private QuickSearchComboBar qs; private Repository selectedRepository; @@ -98,14 +106,26 @@ } private UpdateFiledsState updateFiledsState = null; - public HookPanel(Repository[] repos, Repository toSelect) { + public HookPanel(Repository[] repos) { initComponents(); qs = new QuickSearchComboBar(this); issuePanel.add(qs, BorderLayout.NORTH); issueLabel.setLabelFor(qs.getCommand()); + + Repository[] comboData; + if (repos == null) { + comboData = new Repository[1]; + comboData[0] = null; + } else { + comboData = new Repository[repos.length + 1]; + comboData[0] = null; + if (repos.length != 0) { + System.arraycopy(repos, 0, comboData, 1, repos.length); + } + } - repositoryComboBox.setModel(new DefaultComboBoxModel(repos != null ? repos : new Repository[0])); + repositoryComboBox.setModel(new DefaultComboBoxModel(comboData)); repositoryComboBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -118,18 +138,68 @@ }); repositoryComboBox.addItemListener(this); - if(toSelect != null) { - repositoryComboBox.setSelectedItem(toSelect); - qs.setRepository(toSelect); + enableFields(); + } + + /** + * Selects the given repository in the combo-box if no repository has been + * selected yet by the user. + * If the user had already selected some repository before this method + * was called, this method does nothing. If this method is called at + * the moment the popup of the combo-box is opened, the operation of + * pre-selecting the repository is deferred until the popup is closed. If + * the popup had been displayed at the moment this method was called + * and the user selects some repository during the period since the + * call of this method until the deferred selection takes place, the + * deferred selection operation is cancelled. + * + * @param repoToPreselect repository to preselect + */ + void preselectRepository(final Repository repoToPreselect) { + assert EventQueue.isDispatchThread(); + + if (repoToPreselect == null) { + LOG.finer("preselectRepository(null)"); //NOI18N + return; + } + + if (LOG.isLoggable(FINER)) { + LOG.finer("preselectRepository(" + repoToPreselect.getDisplayName() + ')'); //NOI18N + } + + if (repositoryComboBox.getSelectedItem() != null) { + LOG.finest(" - cancelled - already selected by the user"); //NOI18N + return; + } + + if (repositoryComboBox.isPopupVisible()) { + LOG.finest(" - the popup is visible - deferred"); //NOI18N + repositoryComboBox.addPopupMenuListener(new PopupMenuListener() { + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + LOG.finer("popupMenuWillBecomeInvisible()"); //NOI18N + repositoryComboBox.removePopupMenuListener(this); + } + public void popupMenuCanceled(PopupMenuEvent e) { + LOG.finer("popupMenuCanceled()"); //NOI18N + repositoryComboBox.removePopupMenuListener(this); + LOG.finest(" - processing deferred selection"); //NOI18N + preselectRepositoryUnconditionally(repoToPreselect); + } + }); } else { - if(repositoryComboBox.getItemCount() > 0) { - Repository repo = (Repository) repositoryComboBox.getItemAt(0); - repositoryComboBox.setSelectedItem(repo); - qs.setRepository(repo); - } + preselectRepositoryUnconditionally(repoToPreselect); } - enableFields(); - + } + + private void preselectRepositoryUnconditionally(Repository repoToPreselect) { + assert repositoryComboBox.getSelectedItem() == null; + + if (LOG.isLoggable(FINER)) { + LOG.finer("preselectRepositoryUnconditionally(" + repoToPreselect.getDisplayName() + ')'); //NOI18N + } + + repositoryComboBox.setSelectedItem(repoToPreselect); } Issue getIssue() { diff -r df2f526ba7ed bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/SvnHookImpl.java --- a/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/SvnHookImpl.java Fri May 29 12:27:03 2009 +0200 +++ b/bugtracking.bridge/src/org/netbeans/modules/bugtracking/vcs/SvnHookImpl.java Fri May 29 21:51:39 2009 +0200 @@ -199,21 +199,15 @@ @Override public JPanel createComponent(SvnHookContext context) { - Repository[] repos = BugtrackingUtil.getKnownRepositories(); + File referenceFile; if(context.getFiles().length == 0) { + referenceFile = null; LOG.warning("creating svn hook component for zero files"); // NOI18N - Repository repoToSelect - = BugtrackingOwnerSupport.getInstance() - .getRepository(BugtrackingOwnerSupport.ContextType.ALL_PROJECTS); - panel = new HookPanel(repos, repoToSelect); } else { - File file = context.getFiles()[0]; - Repository repoToSelect = BugtrackingOwnerSupport.getInstance().getRepository(file, false); - if(repoToSelect == null) { - LOG.log(Level.FINE, " could not find issue tracker for " + file); // NOI18N - } - panel = new HookPanel(repos, repoToSelect); + referenceFile = context.getFiles()[0]; } + panel = new HookPanel(getKnownRepositories()); + DefaultRepositorySelector.setup(panel, referenceFile); panel.commitRadioButton.setVisible(false); panel.pushRadioButton.setVisible(false); panel.changeRevisionFormatButton.addActionListener(new ActionListener() { @@ -229,6 +223,18 @@ return panel; } + private static Repository[] getKnownRepositories() { + Repository[] repos; + long startTimeMillis = System.currentTimeMillis(); + repos = BugtrackingUtil.getKnownRepositories(); + long endTimeMillis = System.currentTimeMillis(); + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("BugtrackingUtil.getKnownRepositories() took " //NOI18N + + (endTimeMillis - startTimeMillis) + " ms."); //NOI18N + } + return repos; + } + @Override public String getDisplayName() { return name;