001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.mercurial.ui.status;
043:
044: import org.netbeans.modules.mercurial.HgProgressSupport;
045: import org.netbeans.modules.mercurial.util.HgUtils;
046: import org.netbeans.modules.mercurial.FileInformation;
047: import org.netbeans.modules.mercurial.FileStatusCache;
048: import org.netbeans.modules.mercurial.HgException;
049: import org.netbeans.modules.mercurial.HgFileNode;
050: import org.netbeans.modules.mercurial.HgModuleConfig;
051: import org.netbeans.modules.mercurial.Mercurial;
052: import org.netbeans.modules.mercurial.ui.commit.CommitAction;
053: import org.netbeans.modules.mercurial.ui.update.UpdateAction;
054: import org.netbeans.modules.mercurial.ui.diff.DiffAction;
055: import org.netbeans.modules.mercurial.ui.diff.Setup;
056: import org.netbeans.modules.versioning.spi.VCSContext;
057: import org.netbeans.modules.versioning.util.NoContentPanel;
058: import org.netbeans.api.progress.ProgressHandle;
059: import org.netbeans.api.progress.ProgressHandleFactory;
060: import org.openide.explorer.ExplorerManager;
061: import org.openide.nodes.*;
062: import org.openide.util.Exceptions;
063: import org.openide.windows.TopComponent;
064: import org.openide.util.RequestProcessor;
065: import org.openide.util.NbBundle;
066: import org.openide.LifecycleManager;
067: import javax.swing.*;
068: import javax.swing.border.CompoundBorder;
069: import java.awt.*;
070: import java.awt.image.BufferedImage;
071: import java.awt.event.*;
072: import java.util.*;
073: import java.beans.PropertyChangeListener;
074: import java.beans.PropertyChangeEvent;
075: import java.io.File;
076: import java.util.prefs.PreferenceChangeEvent;
077: import java.util.prefs.PreferenceChangeListener;
078: import java.util.logging.Level;
079: import org.netbeans.modules.mercurial.util.HgCommand;
080: import org.openide.DialogDisplayer;
081: import org.openide.NotifyDescriptor;
082: import org.openide.NotifyDescriptor.Exception;
083:
084: /**
085: * The main class of the Synchronize view, shows and acts on set of file roots.
086: *
087: * @author Maros Sandor
088: */
089: class VersioningPanel extends JPanel implements
090: ExplorerManager.Provider, PreferenceChangeListener,
091: PropertyChangeListener, ActionListener {
092:
093: private ExplorerManager explorerManager;
094: private final HgVersioningTopComponent parentTopComponent;
095: private final Mercurial mercurial;
096: private VCSContext context;
097: private int displayStatuses;
098: private String branchInfo;
099: private SyncTable syncTable;
100: private RequestProcessor.Task refreshViewTask;
101: private Thread refreshViewThread;
102:
103: private HgProgressSupport hgProgressSupport;
104: private static final RequestProcessor rp = new RequestProcessor(
105: "MercurialView", 1, true); // NOI18N
106:
107: private final NoContentPanel noContentComponent = new NoContentPanel();
108:
109: private static final int HG_UPDATE_TARGET_LIMIT = 100;
110:
111: /**
112: * Creates a new Synchronize Panel managed by the given versioning system.
113: *
114: * @param parent enclosing top component
115: */
116: public VersioningPanel(HgVersioningTopComponent parent) {
117: this .parentTopComponent = parent;
118: this .mercurial = Mercurial.getInstance();
119: refreshViewTask = rp.create(new RefreshViewTask());
120: explorerManager = new ExplorerManager();
121: displayStatuses = FileInformation.STATUS_LOCAL_CHANGE;
122: noContentComponent.setLabel(NbBundle.getMessage(
123: VersioningPanel.class, "MSG_No_Changes_All")); // NOI18N
124: syncTable = new SyncTable();
125:
126: initComponents();
127: setVersioningComponent(syncTable.getComponent());
128: reScheduleRefresh(0);
129:
130: // XXX click it in form editor, probbaly requires Mattisse >=v2
131: jPanel2.setFloatable(false);
132: jPanel2.putClientProperty("JToolBar.isRollover", Boolean.TRUE); // NOI18N
133: jPanel2.setLayout(new ToolbarLayout());
134: }
135:
136: public void preferenceChange(PreferenceChangeEvent evt) {
137: if (evt.getKey().startsWith(
138: HgModuleConfig.PROP_COMMIT_EXCLUSIONS)) {
139: repaint();
140: }
141: }
142:
143: public void propertyChange(PropertyChangeEvent evt) {
144:
145: if (evt.getPropertyName() == FileStatusCache.PROP_FILE_STATUS_CHANGED) {
146: FileStatusCache.ChangedEvent changedEvent = (FileStatusCache.ChangedEvent) evt
147: .getNewValue();
148: Mercurial.LOG.log(Level.FINE,
149: "Status.propertyChange(): {0} file: {1}",
150: new Object[] {
151: parentTopComponent.getContentTitle(),
152: changedEvent.getFile() }); // NOI18N
153: if (affectsView(evt)) {
154: reScheduleRefresh(1000);
155: }
156: return;
157: }
158: if (evt.getPropertyName() == Mercurial.PROP_CHANGESET_CHANGED) {
159: Object source = evt.getOldValue();
160: File root = HgUtils.getRootFile(context);
161: Mercurial.LOG.log(Level.FINE,
162: "Mercurial.changesetChanged: source {0} repo {1} ",
163: new Object[] { source, root }); // NOI18N
164: if (root != null && root.equals(source)) {
165: reScheduleRefresh(1000);
166: }
167: return;
168: }
169: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
170: .getPropertyName())) {
171: TopComponent tc = (TopComponent) SwingUtilities
172: .getAncestorOfClass(TopComponent.class, this );
173: if (tc != null) {
174: tc.setActivatedNodes((Node[]) evt.getNewValue());
175: }
176: return;
177: }
178: }
179:
180: /**
181: * Sets roots (directories) to display in the view.
182: *
183: * @param ctx new context if the Versioning panel
184: */
185: void setContext(VCSContext ctx) {
186: context = ctx;
187: //reScheduleRefresh(0);
188: }
189:
190: public ExplorerManager getExplorerManager() {
191: return explorerManager;
192: }
193:
194: public void addNotify() {
195: super .addNotify();
196: HgModuleConfig.getDefault().getPreferences()
197: .addPreferenceChangeListener(this );
198: mercurial.getFileStatusCache().addPropertyChangeListener(this );
199: mercurial.addPropertyChangeListener(this );
200: explorerManager.addPropertyChangeListener(this );
201: reScheduleRefresh(0); // the view does not listen for changes when it is not visible
202: }
203:
204: public void removeNotify() {
205: HgModuleConfig.getDefault().getPreferences()
206: .removePreferenceChangeListener(this );
207: mercurial.getFileStatusCache().removePropertyChangeListener(
208: this );
209: mercurial.removePropertyChangeListener(this );
210: explorerManager.removePropertyChangeListener(this );
211: super .removeNotify();
212: }
213:
214: private void setVersioningComponent(JComponent component) {
215: Component[] children = getComponents();
216: for (int i = 0; i < children.length; i++) {
217: Component child = children[i];
218: if (child != jPanel2) {
219: if (child == component) {
220: return;
221: } else {
222: remove(child);
223: break;
224: }
225: }
226: }
227: GridBagConstraints gbc = new GridBagConstraints();
228: gbc.gridx = 0;
229: gbc.gridy = 2;
230: gbc.gridwidth = GridBagConstraints.REMAINDER;
231: gbc.gridheight = 1;
232: gbc.anchor = GridBagConstraints.FIRST_LINE_START;
233: gbc.fill = GridBagConstraints.BOTH;
234: gbc.weightx = 1;
235: gbc.weighty = 1;
236:
237: add(component, gbc);
238: revalidate();
239: repaint();
240: }
241:
242: /**
243: * Must NOT be run from AWT.
244: */
245: private void setupModels() {
246: if (context == null) {
247: SwingUtilities.invokeLater(new Runnable() {
248: public void run() {
249: syncTable.setTableModel(new SyncFileNode[0]);
250: File root = HgUtils.getRootFile(HgUtils
251: .getCurrentContext(null));
252: /* #126311: Optimize UI for Large repos
253: if (root != null) {
254: String[] info = getRepositoryBranchInfo(root);
255: String rev = info != null ? info[1] : null;
256: String changeset = info != null ? info[2] : null;
257: setRepositoryBranchInfo(rev, changeset);
258: }*/
259: }
260: });
261: return;
262: }
263: // XXX attach Cancelable hook
264: final ProgressHandle ph = ProgressHandleFactory
265: .createHandle(NbBundle.getMessage(
266: VersioningPanel.class,
267: "MSG_Refreshing_Versioning_View")); // NOI18N
268: try {
269: refreshViewThread = Thread.currentThread();
270: Thread.interrupted(); // clear interupted status
271: ph.start();
272: final SyncFileNode[] nodes = getNodes(context,
273: displayStatuses); // takes long
274:
275: if (nodes == null) {
276: return;
277: // finally section
278: }
279:
280: final String[] tableColumns;
281: final String branchTitle;
282: File[] files = context.getRootFiles().toArray(
283: new File[context.getRootFiles().size()]);
284: if (files == null || files.length == 0)
285: return;
286:
287: /* #126311: Optimize UI for Large repos
288: File root = mercurial.getTopmostManagedParent(files[0]);
289: String[] info = getRepositoryBranchInfo(root);
290: String branchName = info != null ? info[0] : null;
291: String rev = info != null ? info[1] : null;
292: String changeset = info != null ? info[2] : null;
293: if (branchName != null && !branchName.equals("")) {
294: branchTitle = NbBundle.getMessage(VersioningPanel.class, "CTL_VersioningView_BranchTitle", branchName); // NOI18N
295: } else {
296: branchTitle = NbBundle.getMessage(VersioningPanel.class, "CTL_VersioningView_UnnamedBranchTitle"); // NOI18N
297: }*/
298: if (nodes.length > 0) {
299: boolean stickyCommon = false;
300: for (int i = 1; i < nodes.length; i++) {
301: if (Thread.interrupted()) {
302: // TODO set model that displays that fact to user
303: return;
304: }
305: }
306: tableColumns = new String[] {
307: SyncFileNode.COLUMN_NAME_NAME,
308: SyncFileNode.COLUMN_NAME_STATUS,
309: SyncFileNode.COLUMN_NAME_PATH };
310: } else {
311: tableColumns = null;
312: }
313: /* #126311: Optimize UI for Large repos
314: setRepositoryBranchInfo(rev, changeset);
315: */
316: SwingUtilities.invokeLater(new Runnable() {
317: public void run() {
318: if (nodes.length > 0) {
319: syncTable.setColumns(tableColumns);
320: setVersioningComponent(syncTable.getComponent());
321: } else {
322: /* #126311: Optimize UI for Large repos
323: parentTopComponent.setBranchTitle(branchTitle); */
324: setVersioningComponent(noContentComponent);
325: }
326: syncTable.setTableModel(nodes);
327: // finally section, it's enqueued after this request
328: }
329: });
330: } finally {
331: SwingUtilities.invokeLater(new Runnable() {
332: public void run() {
333: ph.finish();
334: }
335: });
336: }
337: }
338:
339: private void setRepositoryBranchInfo(String rev, String changeset) {
340: String branchInfo = null;
341: if (rev != null && !rev.equals("-1")) {
342: branchInfo = org.openide.util.NbBundle.getMessage(
343: VersioningPanel.class,
344: "CTL_VersioningView_BranchInfo", // NOI18N
345: rev, changeset);
346: } else {
347: branchInfo = org.openide.util.NbBundle.getMessage(
348: VersioningPanel.class,
349: "CTL_VersioningView_BranchInfoNotCommitted"); // NOI18N
350: }
351: String repositoryStatus = NbBundle.getMessage(
352: VersioningPanel.class,
353: "CTL_VersioningView_StatusTitle", branchInfo); // NOI18N
354: if (!repositoryStatus.equals(statusLabel.getText())) {
355: statusLabel.setText(repositoryStatus);
356: }
357: }
358:
359: private String[] getRepositoryBranchInfo(File root) {
360: String infoStr = null;
361: try {
362: infoStr = HgCommand.getBranchInfo(root);
363: } catch (HgException ex) {
364: Exceptions.printStackTrace(ex);
365: }
366: return infoStr == null ? null : infoStr.split(":");
367: }
368:
369: private SyncFileNode[] getNodes(VCSContext context,
370: int includeStatus) {
371: HgFileNode[] fnodes = mercurial
372: .getNodes(context, includeStatus);
373: SyncFileNode[] nodes = new SyncFileNode[fnodes.length];
374: for (int i = 0; i < fnodes.length; i++) {
375: if (Thread.interrupted())
376: return null;
377: HgFileNode fnode = fnodes[i];
378: nodes[i] = new SyncFileNode(fnode, this );
379: }
380: return nodes;
381: }
382:
383: public int getDisplayStatuses() {
384: return displayStatuses;
385: }
386:
387: public String getDisplayBranchInfo() {
388: return branchInfo;
389: }
390:
391: /**
392: * Performs the "cvs commit" command on all diplayed roots plus "cvs add" for files that are not yet added. // NOI18N
393: */
394: private void onCommitAction() {
395: //TODO: Status Commit Action
396: LifecycleManager.getDefault().saveAll();
397: CommitAction.commit(parentTopComponent.getContentTitle(),
398: context);
399: }
400:
401: /**
402: * Performs the "cvs update" command on all diplayed roots. // NOI18N
403: */
404: private void onUpdateAction() {
405: UpdateAction.update(context);
406: parentTopComponent.contentRefreshed();
407: }
408:
409: /**
410: * Refreshes statuses of all files in the view. It does
411: * that by issuing the "hg status -marduiC" command, updating the cache
412: * and refreshing file nodes.
413: */
414: private void onRefreshAction() {
415: LifecycleManager.getDefault().saveAll();
416: if (context == null || context.getRootFiles().size() == 0) {
417: return;
418: }
419: refreshStatuses();
420: }
421:
422: /**
423: * Programmatically invokes the Refresh action.
424: * Connects to repository and gets recent status.
425: */
426: void performRefreshAction() {
427: refreshStatuses();
428: }
429:
430: /* Async Connects to repository and gets recent status. */
431: private void refreshStatuses() {
432: if (hgProgressSupport != null) {
433: hgProgressSupport.cancel();
434: hgProgressSupport = null;
435: }
436:
437: final String repository = HgUtils.getRootPath(context);
438: if (repository == null)
439: return;
440:
441: RequestProcessor rp = Mercurial.getInstance()
442: .getRequestProcessor(repository);
443: hgProgressSupport = new HgProgressSupport() {
444: public void perform() {
445: StatusAction.executeStatus(context, this );
446: setupModels();
447: }
448: };
449:
450: parentTopComponent.contentRefreshed();
451: hgProgressSupport.start(rp, repository,
452: org.openide.util.NbBundle.getMessage(
453: VersioningPanel.class, "LBL_Refresh_Progress")); // NOI18N
454:
455: }
456:
457: /**
458: * Shows Diff panel for all files in the view. The initial type of diff depends on the sync mode: Local, Remote, All.
459: * In Local mode, the diff shows CURRENT <-> BASE differences. In Remote mode, it shows BASE<->HEAD differences.
460: */
461: private void onDiffAction() {
462: String title = parentTopComponent.getContentTitle();
463: if (displayStatuses == FileInformation.STATUS_LOCAL_CHANGE) {
464: LifecycleManager.getDefault().saveAll();
465: DiffAction.diff(context, Setup.DIFFTYPE_LOCAL, title);
466: } else if (displayStatuses == FileInformation.STATUS_REMOTE_CHANGE) {
467: DiffAction.diff(context, Setup.DIFFTYPE_REMOTE, title);
468: } else {
469: LifecycleManager.getDefault().saveAll();
470: DiffAction.diff(context, Setup.DIFFTYPE_ALL, title);
471: }
472: }
473:
474: private void onDisplayedStatusChanged() {
475: setDisplayStatuses(FileInformation.STATUS_REMOTE_CHANGE
476: | FileInformation.STATUS_LOCAL_CHANGE);
477: noContentComponent.setLabel(NbBundle.getMessage(
478: VersioningPanel.class, "MSG_No_Changes_All")); // NOI18N
479: }
480:
481: private void setDisplayStatuses(int displayStatuses) {
482: this .displayStatuses = displayStatuses;
483: reScheduleRefresh(0);
484: }
485:
486: private boolean affectsView(PropertyChangeEvent event) {
487: FileStatusCache.ChangedEvent changedEvent = (FileStatusCache.ChangedEvent) event
488: .getNewValue();
489: File file = changedEvent.getFile();
490: FileInformation oldInfo = changedEvent.getOldInfo();
491: FileInformation newInfo = changedEvent.getNewInfo();
492: if (oldInfo == null) {
493: if ((newInfo.getStatus() & displayStatuses) == 0)
494: return false;
495: } else {
496: if ((oldInfo.getStatus() & displayStatuses)
497: + (newInfo.getStatus() & displayStatuses) == 0)
498: return false;
499: }
500: return context == null ? false : context.contains(file);
501: }
502:
503: /** Reloads data from cache */
504: private void reScheduleRefresh(int delayMillis) {
505: refreshViewTask.schedule(delayMillis);
506: }
507:
508: // HACK copy&paste HACK, replace by save/restore of column width/position
509: void deserialize() {
510: if (syncTable != null) {
511: SwingUtilities.invokeLater(new Runnable() {
512: public void run() {
513: syncTable.setDefaultColumnSizes();
514: }
515: });
516: }
517: }
518:
519: void focus() {
520: syncTable.focus();
521: }
522:
523: /**
524: * Cancels both:
525: * <ul>
526: * <li>cache data fetching
527: * <li>background cvs -N update
528: * </ul>
529: */
530: public void cancelRefresh() {
531: refreshViewTask.cancel();
532: }
533:
534: private class RefreshViewTask implements Runnable {
535: public void run() {
536: setupModels();
537: }
538: }
539:
540: /**
541: * Hardcoded toolbar layout. It eliminates need
542: * for nested panels their look is hardly maintanable
543: * accross several look and feels
544: * (e.g. strange layouting panel borders on GTK+).
545: *
546: * <p>It sets authoritatively component height and takes
547: * "prefered" width from components itself. // NOI18N
548: *
549: */
550: private class ToolbarLayout implements LayoutManager {
551:
552: /** Expected border height */
553: private int TOOLBAR_HEIGHT_ADJUSTMENT = 4;
554:
555: private int TOOLBAR_SEPARATOR_MIN_WIDTH = 12;
556:
557: /** Cached toolbar height */
558: private int toolbarHeight = -1;
559:
560: /** Guard for above cache. */
561: private Dimension parentSize;
562:
563: private Set<JComponent> adjusted = new HashSet<JComponent>();
564:
565: public void removeLayoutComponent(Component comp) {
566: }
567:
568: public void layoutContainer(Container parent) {
569: Dimension dim = VersioningPanel.this .getSize();
570: Dimension max = parent.getSize();
571:
572: int reminder = max.width - minimumLayoutSize(parent).width;
573:
574: int components = parent.getComponentCount();
575: int horizont = 0;
576: for (int i = 0; i < components; i++) {
577: JComponent comp = (JComponent) parent.getComponent(i);
578: if (comp.isVisible() == false)
579: continue;
580: comp.setLocation(horizont, 0);
581: Dimension pref = comp.getPreferredSize();
582: int width = pref.width;
583: if (comp instanceof JSeparator
584: && ((dim.height - dim.width) <= 0)) {
585: width = Math
586: .max(width, TOOLBAR_SEPARATOR_MIN_WIDTH);
587: }
588: if (comp instanceof JProgressBar && reminder > 0) {
589: width += reminder;
590: }
591: // if (comp == getMiniStatus()) {
592: // width = reminder;
593: // }
594:
595: // in column layout use taller toolbar
596: int height = getToolbarHeight(dim) - 1;
597: comp.setSize(width, height); // 1 verySoftBevel compensation
598: horizont += width;
599: }
600: }
601:
602: public void addLayoutComponent(String name, Component comp) {
603: }
604:
605: public Dimension minimumLayoutSize(Container parent) {
606:
607: // in column layout use taller toolbar
608: Dimension dim = VersioningPanel.this .getSize();
609: int height = getToolbarHeight(dim);
610:
611: int components = parent.getComponentCount();
612: int horizont = 0;
613: for (int i = 0; i < components; i++) {
614: Component comp = parent.getComponent(i);
615: if (comp.isVisible() == false)
616: continue;
617: if (comp instanceof AbstractButton) {
618: adjustToobarButton((AbstractButton) comp);
619: } else {
620: adjustToolbarComponentSize((JComponent) comp);
621: }
622: Dimension pref = comp.getPreferredSize();
623: int width = pref.width;
624: if (comp instanceof JSeparator
625: && ((dim.height - dim.width) <= 0)) {
626: width = Math
627: .max(width, TOOLBAR_SEPARATOR_MIN_WIDTH);
628: }
629: horizont += width;
630: }
631:
632: return new Dimension(horizont, height);
633: }
634:
635: public Dimension preferredLayoutSize(Container parent) {
636: // Eliminates double height toolbar problem
637: Dimension dim = VersioningPanel.this .getSize();
638: int height = getToolbarHeight(dim);
639:
640: return new Dimension(Integer.MAX_VALUE, height);
641: }
642:
643: /**
644: * Computes vertical toolbar components height that can used for layout manager hinting.
645: * @return size based on font size and expected border.
646: */
647: private int getToolbarHeight(Dimension parent) {
648:
649: if (parentSize == null
650: || (parentSize.equals(parent) == false)) {
651: parentSize = parent;
652: toolbarHeight = -1;
653: }
654:
655: if (toolbarHeight == -1) {
656: BufferedImage image = new BufferedImage(1, 1,
657: BufferedImage.TYPE_BYTE_GRAY);
658: Graphics2D g = image.createGraphics();
659: UIDefaults def = UIManager.getLookAndFeelDefaults();
660:
661: int height = 0;
662: String[] fonts = { "Label.font", "Button.font",
663: "ToggleButton.font" }; // NOI18N
664: for (int i = 0; i < fonts.length; i++) {
665: Font f = def.getFont(fonts[i]);
666: FontMetrics fm = g.getFontMetrics(f);
667: height = Math.max(height, fm.getHeight());
668: }
669: toolbarHeight = height + TOOLBAR_HEIGHT_ADJUSTMENT;
670: if ((parent.height - parent.width) > 0) {
671: toolbarHeight += TOOLBAR_HEIGHT_ADJUSTMENT;
672: }
673: }
674:
675: return toolbarHeight;
676: }
677:
678: /** Toolbar controls must be smaller and should be transparent*/
679: private void adjustToobarButton(final AbstractButton button) {
680:
681: if (adjusted.contains(button))
682: return;
683:
684: // workaround for Ocean L&F clutter - toolbars use gradient.
685: // To make the gradient visible under buttons the content area must not
686: // be filled. To support rollover it must be temporarily filled
687: if (button instanceof JToggleButton == false) {
688: button.setContentAreaFilled(false);
689: button.setMargin(new Insets(0, 3, 0, 3));
690: button.setBorderPainted(false);
691: button.addMouseListener(new MouseAdapter() {
692: public void mouseEntered(MouseEvent e) {
693: button.setContentAreaFilled(true);
694: button.setBorderPainted(true);
695: }
696:
697: public void mouseExited(MouseEvent e) {
698: button.setContentAreaFilled(false);
699: button.setBorderPainted(false);
700: }
701: });
702: }
703:
704: adjustToolbarComponentSize(button);
705: }
706:
707: private void adjustToolbarComponentSize(JComponent button) {
708:
709: if (adjusted.contains(button))
710: return;
711:
712: // as we cannot get the button small enough using the margin and border...
713: if (button.getBorder() instanceof CompoundBorder) { // from BasicLookAndFeel
714: Dimension pref = button.getPreferredSize();
715:
716: // XXX #41827 workaround w2k, that adds eclipsis (...) instead of actual text
717: if ("Windows"
718: .equals(UIManager.getLookAndFeel().getID())) { // NOI18N
719: pref.width += 9;
720: }
721: button.setPreferredSize(pref);
722: }
723:
724: adjusted.add(button);
725: }
726: }
727:
728: /** This method is called from within the constructor to
729: * initialize the form.
730: * WARNING: Do NOT modify this code. The content of this method is
731: * always regenerated by the Form Editor.
732: */
733: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
734: private void initComponents() {
735: java.awt.GridBagConstraints gridBagConstraints;
736:
737: jComboBox1 = new javax.swing.JComboBox();
738: jPanel2 = new javax.swing.JToolBar();
739: jPanel4 = new javax.swing.JPanel();
740: statusLabel = new javax.swing.JLabel();
741: jPanel1 = new javax.swing.JPanel();
742: jSeparator1 = new javax.swing.JSeparator();
743: jSeparator2 = new javax.swing.JSeparator();
744: btnRefresh = new javax.swing.JButton();
745: btnDiff = new javax.swing.JButton();
746: jPanel3 = new javax.swing.JPanel();
747: btnUpdate = new javax.swing.JButton();
748: btnCommit = new javax.swing.JButton();
749: jPanel5 = new javax.swing.JPanel();
750:
751: jComboBox1
752: .setModel(new javax.swing.DefaultComboBoxModel(
753: new String[] { "Item 1", "Item 2", "Item 3",
754: "Item 4" }));
755:
756: setLayout(new java.awt.GridBagLayout());
757:
758: jPanel2.setBorderPainted(false);
759:
760: jPanel4.setOpaque(false);
761: jPanel2.add(jPanel4);
762:
763: java.util.ResourceBundle bundle = java.util.ResourceBundle
764: .getBundle("org/netbeans/modules/mercurial/ui/status/Bundle"); // NOI18N
765: statusLabel.setText(bundle
766: .getString("CTL_Versioning_Status_Table_Title")); // NOI18N
767: statusLabel
768: .setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
769: statusLabel.setMaximumSize(new java.awt.Dimension(120, 17));
770: statusLabel.setMinimumSize(new java.awt.Dimension(120, 17));
771: jPanel2.add(statusLabel);
772: statusLabel.getAccessibleContext().setAccessibleName(
773: bundle.getString("CTL_Versioning_Status_Table_Title")); // NOI18N
774:
775: jPanel1.setOpaque(false);
776: jPanel1.add(jSeparator1);
777:
778: jPanel2.add(jPanel1);
779:
780: jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
781: jPanel2.add(jSeparator2);
782:
783: btnRefresh
784: .setIcon(new javax.swing.ImageIcon(
785: getClass()
786: .getResource(
787: "/org/netbeans/modules/mercurial/resources/icons/refresh.png"))); // NOI18N
788: btnRefresh.setToolTipText(org.openide.util.NbBundle.getMessage(
789: VersioningPanel.class,
790: "CTL_Synchronize_Action_Refresh_Tooltip")); // NOI18N
791: btnRefresh.setMaximumSize(new java.awt.Dimension(28, 28));
792: btnRefresh.setMinimumSize(new java.awt.Dimension(28, 28));
793: btnRefresh.setPreferredSize(new java.awt.Dimension(22, 25));
794: btnRefresh.addActionListener(this );
795: jPanel2.add(btnRefresh);
796: btnRefresh.getAccessibleContext().setAccessibleName(
797: "Refresh Status");
798:
799: btnDiff
800: .setIcon(new javax.swing.ImageIcon(
801: getClass()
802: .getResource(
803: "/org/netbeans/modules/mercurial/resources/icons/diff.png"))); // NOI18N
804: btnDiff.setToolTipText(bundle
805: .getString("CTL_Synchronize_Action_Diff_Tooltip")); // NOI18N
806: btnDiff.setFocusable(false);
807: btnDiff.setPreferredSize(new java.awt.Dimension(22, 25));
808: btnDiff.addActionListener(this );
809: jPanel2.add(btnDiff);
810: btnDiff.getAccessibleContext().setAccessibleName("Diff All");
811:
812: jPanel3.setOpaque(false);
813: jPanel2.add(jPanel3);
814:
815: btnUpdate
816: .setIcon(new javax.swing.ImageIcon(
817: getClass()
818: .getResource(
819: "/org/netbeans/modules/mercurial/resources/icons/update.png"))); // NOI18N
820: btnUpdate.setToolTipText(bundle
821: .getString("CTL_Synchronize_Action_Update_Tooltip")); // NOI18N
822: btnUpdate.setFocusable(false);
823: btnUpdate.setPreferredSize(new java.awt.Dimension(22, 25));
824: btnUpdate.addActionListener(this );
825: jPanel2.add(btnUpdate);
826: btnUpdate.getAccessibleContext().setAccessibleName("Update");
827:
828: btnCommit
829: .setIcon(new javax.swing.ImageIcon(
830: getClass()
831: .getResource(
832: "/org/netbeans/modules/mercurial/resources/icons/commit.png"))); // NOI18N
833: btnCommit.setToolTipText(bundle
834: .getString("CTL_CommitForm_Action_Commit_Tooltip")); // NOI18N
835: btnCommit.setFocusable(false);
836: btnCommit.setPreferredSize(new java.awt.Dimension(22, 25));
837: btnCommit.addActionListener(this );
838: jPanel2.add(btnCommit);
839: btnCommit.getAccessibleContext().setAccessibleName("Commit");
840:
841: jPanel5.setOpaque(false);
842: jPanel2.add(jPanel5);
843:
844: gridBagConstraints = new java.awt.GridBagConstraints();
845: gridBagConstraints.gridx = 0;
846: gridBagConstraints.gridy = 0;
847: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
848: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
849: gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
850: gridBagConstraints.weightx = 1.0;
851: gridBagConstraints.insets = new java.awt.Insets(3, 0, 3, 0);
852: add(jPanel2, gridBagConstraints);
853: }
854:
855: // Code for dispatching events from components to event handlers.
856:
857: public void actionPerformed(java.awt.event.ActionEvent evt) {
858: if (evt.getSource() == btnRefresh) {
859: VersioningPanel.this .btnRefreshActionPerformed(evt);
860: } else if (evt.getSource() == btnDiff) {
861: VersioningPanel.this .btnDiffActionPerformed(evt);
862: } else if (evt.getSource() == btnUpdate) {
863: VersioningPanel.this .btnUpdateActionPerformed(evt);
864: } else if (evt.getSource() == btnCommit) {
865: VersioningPanel.this .btnCommitActionPerformed(evt);
866: }
867: }// </editor-fold>//GEN-END:initComponents
868:
869: private void btnRefreshActionPerformed(
870: java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshActionPerformed
871: onRefreshAction();
872: }//GEN-LAST:event_btnRefreshActionPerformed
873:
874: private void btnDiffActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDiffActionPerformed
875: onDiffAction();
876: }//GEN-LAST:event_btnDiffActionPerformed
877:
878: private void btnUpdateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUpdateActionPerformed
879: onUpdateAction();
880: }//GEN-LAST:event_btnUpdateActionPerformed
881:
882: private void btnCommitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCommitActionPerformed
883: onCommitAction();
884: }//GEN-LAST:event_btnCommitActionPerformed
885:
886: // Variables declaration - do not modify//GEN-BEGIN:variables
887: private javax.swing.JButton btnCommit;
888: private javax.swing.JButton btnDiff;
889: private javax.swing.JButton btnRefresh;
890: private javax.swing.JButton btnUpdate;
891: private javax.swing.JComboBox jComboBox1;
892: private javax.swing.JPanel jPanel1;
893: private javax.swing.JToolBar jPanel2;
894: private javax.swing.JPanel jPanel3;
895: private javax.swing.JPanel jPanel4;
896: private javax.swing.JPanel jPanel5;
897: private javax.swing.JSeparator jSeparator1;
898: private javax.swing.JSeparator jSeparator2;
899: private javax.swing.JLabel statusLabel;
900: // End of variables declaration//GEN-END:variables
901:
902: }
|