PageRenderTime 23ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/subversion/src/org/netbeans/modules/subversion/ui/copy/CopyDialog.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 376 lines | 267 code | 27 blank | 82 comment | 57 complexity | 274c2a684b95359c368b1ded85950aff MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.netbeans.modules.subversion.ui.copy;
  45. import java.awt.Component;
  46. import java.awt.Dialog;
  47. import java.awt.EventQueue;
  48. import java.awt.event.ActionEvent;
  49. import java.awt.event.ActionListener;
  50. import java.util.Comparator;
  51. import java.util.HashMap;
  52. import java.util.HashSet;
  53. import java.util.LinkedList;
  54. import java.util.List;
  55. import java.util.Map;
  56. import java.util.Set;
  57. import java.util.TreeMap;
  58. import java.util.regex.Matcher;
  59. import java.util.regex.Pattern;
  60. import javax.swing.ComboBoxModel;
  61. import javax.swing.DefaultComboBoxModel;
  62. import javax.swing.DefaultListCellRenderer;
  63. import javax.swing.JButton;
  64. import javax.swing.JComboBox;
  65. import javax.swing.JList;
  66. import javax.swing.JPanel;
  67. import javax.swing.event.PopupMenuEvent;
  68. import javax.swing.event.PopupMenuListener;
  69. import javax.swing.text.JTextComponent;
  70. import org.netbeans.modules.subversion.RepositoryFile;
  71. import org.netbeans.modules.subversion.SvnModuleConfig;
  72. import org.netbeans.modules.versioning.util.Utils;
  73. import org.openide.DialogDescriptor;
  74. import org.openide.DialogDisplayer;
  75. import org.openide.util.HelpCtx;
  76. import org.openide.util.NbBundle;
  77. import org.tigris.subversion.svnclientadapter.utils.SVNUrlUtils;
  78. /**
  79. *
  80. * @author Tomas Stupka
  81. */
  82. public abstract class CopyDialog {
  83. private DialogDescriptor dialogDescriptor;
  84. private JButton okButton, cancelButton;
  85. private JPanel panel;
  86. private static final Pattern TEMPLATE_PATTERN_BRANCH = Pattern.compile("^(.*/)*?((?:branches|tags)/(?:.+?))(/.*)+$"); //NOI18N
  87. private static final Pattern TEMPLATE_PATTERN_TRUNK = Pattern.compile("^(.*/)*?(trunk)(/.*)+$"); //NOI18N
  88. private static final String BRANCHES_FOLDER = "branches"; //NOI18N
  89. private static final String TRUNK_FOLDER = "trunk"; //NOI18N
  90. private static final String BRANCH_TEMPLATE = "[BRANCH_NAME]"; //NOI18N
  91. private static final String SEP = "----------"; //NOI18N
  92. private static final String MORE_BRANCHES = NbBundle.getMessage(CopyDialog.class, "LBL_CopyDialog.moreBranchesAndTags"); //NOI18N
  93. private Set<JComboBox> urlComboBoxes;
  94. CopyDialog(JPanel panel, String title, String okLabel) {
  95. this.panel = panel;
  96. okButton = new JButton(okLabel);
  97. okButton.getAccessibleContext().setAccessibleDescription(okLabel);
  98. cancelButton = new JButton(org.openide.util.NbBundle.getMessage(CopyDialog.class, "CTL_Copy_Cancel")); // NOI18N
  99. cancelButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CopyDialog.class, "CTL_Copy_Cancel")); // NOI18N
  100. dialogDescriptor = new DialogDescriptor(panel, title, true, new Object[] {okButton, cancelButton},
  101. okButton, DialogDescriptor.DEFAULT_ALIGN, new HelpCtx(this.getClass()), null);
  102. okButton.setEnabled(false);
  103. Dialog dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
  104. dialog.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CopyDialog.class, "CTL_Title")); // NOI18N
  105. }
  106. protected void setupUrlComboBox (RepositoryFile repositoryFile, JComboBox cbo) {
  107. if(cbo==null) {
  108. return;
  109. }
  110. List<String> recentFolders = new LinkedList<String>(Utils.getStringList(SvnModuleConfig.getDefault().getPreferences(), CopyDialog.class.getName()));
  111. Map<String, String> comboItems = setupModel(cbo, repositoryFile, recentFolders);
  112. cbo.setRenderer(new LocationRenderer(comboItems));
  113. getUrlComboBoxes().add(cbo);
  114. }
  115. private Set<JComboBox> getUrlComboBoxes () {
  116. if(urlComboBoxes == null) {
  117. urlComboBoxes = new HashSet<JComboBox>();
  118. }
  119. return urlComboBoxes;
  120. }
  121. protected JPanel getPanel() {
  122. return panel;
  123. }
  124. boolean showDialog() {
  125. Dialog dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
  126. dialog.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(CopyDialog.class, "CTL_Title")); // NOI18N
  127. dialog.setVisible(true);
  128. boolean ret = dialogDescriptor.getValue()==okButton;
  129. if(ret) {
  130. storeValidValues();
  131. }
  132. return ret;
  133. }
  134. private void storeValidValues() {
  135. for (JComboBox cbo : urlComboBoxes) {
  136. Object item = cbo.getEditor().getItem();
  137. if(item != null && !item.equals("")) { // NOI18N
  138. Utils.insert(SvnModuleConfig.getDefault().getPreferences(), CopyDialog.class.getName(), (String) item, -1);
  139. }
  140. }
  141. }
  142. protected JButton getOKButton() {
  143. return okButton;
  144. }
  145. /**
  146. * Model has three categories:
  147. * trunk/path (1)
  148. * -----
  149. * branches and tags (2)
  150. * More Branches and Tags
  151. * -----
  152. * relevant recent urls (3) - those ending with the same file name
  153. * @param cbo
  154. * @param repositoryFile
  155. * @param recentFolders
  156. * @return
  157. */
  158. static Map<String, String> setupModel (JComboBox cbo, RepositoryFile repositoryFile, List<String> recentFolders) {
  159. Map<String, String> locations = new HashMap<String, String>(Math.min(recentFolders.size(), 10));
  160. List<String> model = new LinkedList<String>();
  161. // all category in the model is sorted by name ignoring case
  162. Comparator comparator = new Comparator<String>() {
  163. @Override
  164. public int compare (String o1, String o2) {
  165. return o1.compareToIgnoreCase(o2);
  166. }
  167. };
  168. // category 3
  169. TreeMap<String, String> relatedLocations = new TreeMap<String, String>(comparator);
  170. // category 2
  171. TreeMap<String, String> branchLocations = new TreeMap<String, String>(comparator);
  172. String relativePath = SVNUrlUtils.getRelativePath(repositoryFile.getRepositoryUrl(), repositoryFile.getFileUrl());
  173. String fileName = repositoryFile.getName();
  174. String[] branchPathSegments = getBranchPathSegments(relativePath);
  175. String pathInBranch = branchPathSegments[2];
  176. String preselectedPath = null;
  177. for (String recentUrl : recentFolders) {
  178. if (pathInBranch != null && branchLocations.size() < 10) {
  179. // repository seems to have the recommended branch structure
  180. String[] pathSegments = getBranchPathSegments(recentUrl);
  181. if (branchPathSegments[0].equals(pathSegments[0]) && !TRUNK_FOLDER.equals(pathSegments[1])) {
  182. // this is a branch or a tag, so get the branch or tag name and build the url relevant for the given file
  183. String branchPrefix = pathSegments[0] + pathSegments[1];
  184. String loc = branchPrefix + '/' + pathInBranch;
  185. // we also emphasize branch/tag name in the renderer, so build the rendered string
  186. branchLocations.put(loc, getHtmlVersion(branchPrefix, pathInBranch));
  187. if (preselectedPath == null) {
  188. preselectedPath = loc;
  189. }
  190. }
  191. }
  192. if (recentUrl.endsWith("/" + fileName) && relatedLocations.size() < 10) {
  193. // this is a relevant (3) url, so add it
  194. if (pathInBranch == null && preselectedPath == null) {
  195. preselectedPath = recentUrl;
  196. }
  197. relatedLocations.put(recentUrl, null);
  198. }
  199. }
  200. if (pathInBranch != null) {
  201. // now let's do some corrections
  202. // add the single item to cat 1
  203. String pref = TRUNK_FOLDER;
  204. if (branchPathSegments[0] != null) {
  205. pref = branchPathSegments[0] + pref;
  206. }
  207. String loc = pref + "/" + pathInBranch;
  208. locations.put(loc, getHtmlVersion(pref, pathInBranch));
  209. model.add(loc);
  210. model.add(SEP);
  211. // add cat 2 to the model
  212. model.addAll(branchLocations.keySet());
  213. locations.putAll(branchLocations);
  214. model.add(MORE_BRANCHES);
  215. if (preselectedPath == null) {
  216. pref = BRANCHES_FOLDER;
  217. if (branchPathSegments[0] != null) {
  218. pref = branchPathSegments[0] + pref;
  219. }
  220. preselectedPath = pref + "/" + BRANCH_TEMPLATE + "/" + pathInBranch; //NOI18N
  221. }
  222. SelectionListener list = new SelectionListener(repositoryFile, cbo, branchPathSegments[0]);
  223. cbo.addActionListener(list);
  224. cbo.addPopupMenuListener(list);
  225. }
  226. // do not duplicate entries, so remove all items from (3) that are already in (2)
  227. relatedLocations.keySet().removeAll(locations.keySet());
  228. locations.putAll(relatedLocations);
  229. if (!model.isEmpty() && !relatedLocations.isEmpty()) {
  230. model.add(SEP);
  231. }
  232. model.addAll(relatedLocations.keySet());
  233. ComboBoxModel rootsModel = new DefaultComboBoxModel(model.toArray(new String[model.size()]));
  234. cbo.setModel(rootsModel);
  235. JTextComponent comp = (JTextComponent) cbo.getEditor().getEditorComponent();
  236. if (preselectedPath != null) {
  237. comp.setText(preselectedPath);
  238. if (pathInBranch != null) {
  239. // select the branch name in the offered text - for easy editing
  240. String[] pathSegments = getBranchPathSegments(preselectedPath);
  241. String branchPrefix = pathSegments[0] + pathSegments[1];
  242. int pos = branchPrefix.lastIndexOf('/') + 1;
  243. if (pos > 0) {
  244. comp.setCaretPosition(pos);
  245. comp.moveCaretPosition(branchPrefix.length());
  246. }
  247. }
  248. }
  249. return locations;
  250. }
  251. /**
  252. * Splits a given relative path into segments:
  253. * <ol>
  254. * <li>folder prefix where branches/tags/trunk lies in the repository. <code>null</code> for url where trunk/branches/tags are directly in the root folder</li>
  255. * <li>name of a branch or tag prefixed with the branches or tags prefix, or just simply "trunk" if the url is part of the trunk</li>
  256. * <li>path to the resource inside trunk/branch/tag</li>
  257. * </ol>
  258. * @param relativePath
  259. * @return
  260. */
  261. private static String[] getBranchPathSegments (String relativePath) {
  262. String prefix = null;
  263. String path = null;
  264. String branchName = null;
  265. for (Pattern p : new Pattern[] { TEMPLATE_PATTERN_BRANCH, TEMPLATE_PATTERN_TRUNK}) {
  266. Matcher m = p.matcher(relativePath);
  267. if (m.matches()) {
  268. prefix = m.group(1);
  269. if (prefix == null) {
  270. prefix = ""; //NOI18N
  271. }
  272. branchName = m.group(2);
  273. path = m.group(3);
  274. break;
  275. }
  276. }
  277. if (path != null) {
  278. path = path.substring(1);
  279. }
  280. return new String[] { prefix, branchName, path };
  281. }
  282. private static String getHtmlVersion (String branchPrefix, String relativePathInBranch) {
  283. int branchStart = branchPrefix.lastIndexOf('/');
  284. if (branchStart > 0) {
  285. return new StringBuilder(2 * (branchPrefix.length() + relativePathInBranch.length())).append("<html>") //NOI18N
  286. .append(branchPrefix.substring(0, branchStart + 1)).append("<strong>").append(branchPrefix.substring(branchStart + 1)) //NOI18N
  287. .append("</strong>").append('/').append(relativePathInBranch).append("</html>").toString(); //NOI18N
  288. }
  289. return null;
  290. }
  291. private static class LocationRenderer extends DefaultListCellRenderer {
  292. private final Map<String, String> empLocations;
  293. public LocationRenderer (Map<String, String> locations) {
  294. this.empLocations = locations;
  295. }
  296. @Override
  297. public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
  298. String html;
  299. if (value instanceof String && (html = empLocations.get(((String) value))) != null) {
  300. value = html;
  301. }
  302. return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  303. }
  304. }
  305. private static class SelectionListener implements ActionListener, PopupMenuListener {
  306. private final RepositoryFile repositoryFile;
  307. private final JComboBox combo;
  308. private boolean popupOn;
  309. private final String branchesFolderPath;
  310. public SelectionListener (RepositoryFile repositoryFile, JComboBox combo, String branchesFolderPath) {
  311. this.repositoryFile = repositoryFile;
  312. this.combo = combo;
  313. this.branchesFolderPath = branchesFolderPath;
  314. }
  315. @Override
  316. public void actionPerformed (ActionEvent e) {
  317. if (e.getSource() == combo) {
  318. EventQueue.invokeLater(new Runnable() {
  319. @Override
  320. public void run () {
  321. if (!popupOn && (combo.getSelectedItem() == SEP || combo.getSelectedItem() == MORE_BRANCHES)) {
  322. String text = ""; //NOI18N
  323. if (combo.getSelectedItem() == MORE_BRANCHES) {
  324. BranchPicker picker = new BranchPicker(repositoryFile, branchesFolderPath);
  325. if (picker.openDialog()) {
  326. String relativePath = SVNUrlUtils.getRelativePath(repositoryFile.getRepositoryUrl(), repositoryFile.getFileUrl());
  327. text = picker.getSelectedPath() + "/" + getBranchPathSegments(relativePath)[2]; //NOI18N
  328. }
  329. }
  330. ((JTextComponent) combo.getEditor().getEditorComponent()).setText(text); //NOI18N
  331. }
  332. }
  333. });
  334. }
  335. }
  336. @Override
  337. public void popupMenuWillBecomeVisible (PopupMenuEvent e) {
  338. popupOn = true;
  339. }
  340. @Override
  341. public void popupMenuWillBecomeInvisible (PopupMenuEvent e) {
  342. popupOn = false;
  343. }
  344. @Override
  345. public void popupMenuCanceled (PopupMenuEvent e) {
  346. popupOn = true;
  347. }
  348. }
  349. }