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 javax.swing.SwingUtilities;
045: import org.netbeans.modules.versioning.spi.VCSContext;
046: import org.openide.util.*;
047: import org.openide.windows.TopComponent;
048: import org.openide.windows.WindowManager;
049: import org.openide.util.NbBundle;
050: import org.openide.util.HelpCtx;
051:
052: import java.awt.BorderLayout;
053: import java.awt.Cursor;
054: import java.io.*;
055: import java.util.logging.Level;
056: import org.netbeans.modules.mercurial.Mercurial;
057: import org.netbeans.modules.mercurial.util.HgUtils;
058:
059: /**
060: * Top component of the Versioning view.
061: *
062: * @author Maros Sandor
063: */
064: public class HgVersioningTopComponent extends TopComponent {
065:
066: private static final long serialVersionUID = 1L;
067:
068: private VersioningPanel syncPanel;
069: private VCSContext context;
070: private String contentTitle;
071: private String branchTitle;
072: private long lastUpdateTimestamp;
073: private static final String PREFERRED_ID = "hgversioning"; // NOI18N
074:
075: private static HgVersioningTopComponent instance;
076:
077: public HgVersioningTopComponent() {
078: putClientProperty("SlidingName", NbBundle.getMessage(
079: HgVersioningTopComponent.class,
080: "CTL_Versioning_TopComponent_Title")); //NOI18N
081:
082: setName(NbBundle.getMessage(HgVersioningTopComponent.class,
083: "CTL_Versioning_TopComponent_Title")); // NOI18N
084: setIcon(org.openide.util.Utilities
085: .loadImage("org/netbeans/modules/mercurial/resources/icons/versioning-view.png")); // NOI18N
086: setLayout(new BorderLayout());
087: getAccessibleContext().setAccessibleDescription(
088: NbBundle.getMessage(HgVersioningTopComponent.class,
089: "CTL_Versioning_TopComponent_Title")); // NOI18N
090: syncPanel = new VersioningPanel(this );
091: add(syncPanel);
092: }
093:
094: public HelpCtx getHelpCtx() {
095: return new HelpCtx(getClass());
096: }
097:
098: protected void componentActivated() {
099: updateTitle();
100: syncPanel.focus();
101: }
102:
103: protected void componentOpened() {
104: super .componentOpened();
105: refreshContent();
106: }
107:
108: protected void componentClosed() {
109: super .componentClosed();
110: }
111:
112: private void refreshContent() {
113: if (syncPanel == null)
114: return; // the component is not showing => nothing to refresh
115: updateTitle();
116: syncPanel.setContext(context);
117: }
118:
119: /**
120: * Sets the 'content' portion of Versioning component title.
121: * Title pattern: Versioning[ - contentTitle[ - branchTitle]] (10 minutes ago)
122: *
123: * @param contentTitle a new content title, e.g. "2 projects" // NOI18N
124: */
125: public void setContentTitle(String contentTitle) {
126: this .contentTitle = contentTitle;
127: updateTitle();
128: }
129:
130: /**
131: * Sets the 'branch' portion of Versioning component title.
132: * Title pattern: Versioning[ - contentTitle[ - branchTitle]] (10 minutes ago)
133: *
134: * @param branchTitle a new content title, e.g. "release40" branch // NOI18N
135: */
136: void setBranchTitle(String branchTitle) {
137: this .branchTitle = branchTitle;
138: updateTitle();
139: }
140:
141: public void contentRefreshed() {
142: lastUpdateTimestamp = System.currentTimeMillis();
143: updateTitle();
144: }
145:
146: private void updateTitle() {
147: SwingUtilities.invokeLater(new Runnable() {
148: public void run() {
149:
150: if (contentTitle == null) {
151: setName(NbBundle.getMessage(
152: HgVersioningTopComponent.class,
153: "CTL_Versioning_TopComponent_Title")); // NOI18N
154: } else {
155: File baseFile = HgUtils.getRootFile(context);
156: String name = "";
157: if (baseFile != null) {
158: name = baseFile.getName();
159: }
160:
161: if (branchTitle == null) {
162: setName(NbBundle
163: .getMessage(
164: HgVersioningTopComponent.class,
165: "CTL_Versioning_TopComponent_MultiTitle",
166: contentTitle,
167: name.equals(contentTitle) ? ""
168: : "[" + name + "]")); // NOI18N
169: } else {
170: setName(NbBundle
171: .getMessage(
172: HgVersioningTopComponent.class,
173: "CTL_Versioning_TopComponent_Title_ContentBranch",
174: contentTitle,
175: name.equals(contentTitle) ? ""
176: : "[" + name + "] ",
177: branchTitle)); // NOI18N
178: }
179: }
180: }
181: });
182: }
183:
184: String getContentTitle() {
185: return contentTitle;
186: }
187:
188: /**
189: * Gets default instance. Do not use directly: reserved for *.settings files only,
190: * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
191: * To obtain the singleton instance, use {@link findInstance}.
192: */
193: public static synchronized HgVersioningTopComponent getDefault() {
194: if (instance == null) {
195: instance = new HgVersioningTopComponent();
196: }
197: return instance;
198: }
199:
200: /**
201: * Obtain the HgVersioningTopComponent instance. Never call {@link #getDefault} directly!
202: */
203: public static synchronized HgVersioningTopComponent findInstance() {
204: TopComponent win = WindowManager.getDefault().findTopComponent(
205: PREFERRED_ID);
206: if (win == null) {
207: Mercurial.LOG
208: .log(
209: Level.FINE,
210: "Cannot find "
211: + PREFERRED_ID
212: + " component. It will not be located properly in the window system."); // NOI18N
213: return getDefault();
214: }
215: if (win instanceof HgVersioningTopComponent) {
216: return (HgVersioningTopComponent) win;
217: }
218: Mercurial.LOG
219: .log(Level.FINE,
220: "There seem to be multiple components with the '"
221: + PREFERRED_ID + // NOI18N
222: "' ID. That is a potential source of errors and unexpected behavior."); // NOI18N
223: return getDefault();
224: }
225:
226: public int getPersistenceType() {
227: return TopComponent.PERSISTENCE_ALWAYS;
228: }
229:
230: /** replaces this in object stream */
231: public Object writeReplace() {
232: return new ResolvableHelper();
233: }
234:
235: protected String preferredID() {
236: return PREFERRED_ID;
237: }
238:
239: final static class ResolvableHelper implements Serializable {
240: private static final long serialVersionUID = 1L;
241:
242: public Object readResolve() {
243: return HgVersioningTopComponent.getDefault();
244: }
245: }
246:
247: /**
248: * Programmatically invokes the Refresh action.
249: */
250: public void performRefreshAction() {
251: syncPanel.performRefreshAction();
252: }
253:
254: /**
255: * Sets files/folders the user wants to synchronize. They are typically activated (selected) nodes.
256: *
257: * @param ctx new context of the Versioning view
258: */
259: public void setContext(VCSContext ctx) {
260: syncPanel.cancelRefresh();
261:
262: if (ctx == null) {
263: setName(NbBundle.getMessage(HgVersioningTopComponent.class,
264: "MSG_Preparing")); // NOI18N
265: setEnabled(false);
266: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
267: } else {
268: setEnabled(true);
269: setCursor(Cursor.getDefaultCursor());
270: context = ctx;
271: syncPanel.setContext(ctx);
272: setBranchTitle(NbBundle.getMessage(
273: HgVersioningTopComponent.class,
274: "CTL_VersioningView_UnnamedBranchTitle")); // NOI18N
275: refreshContent();
276: }
277: setToolTipText(getContextFilesList(ctx, NbBundle.getMessage(
278: HgVersioningTopComponent.class,
279: "CTL_Versioning_TopComponent_Title"))); // NOI18N
280: }
281:
282: private String getContextFilesList(VCSContext ctx, String def) {
283: if (ctx == null || ctx.getRootFiles().size() == 0)
284: return def;
285: StringBuffer sb = new StringBuffer(200);
286: sb.append("<html>"); // NOI18N
287: for (File file : ctx.getRootFiles()) {
288: sb.append(file.getAbsolutePath());
289: sb.append("<br>"); // NOI18N
290: }
291: sb.delete(sb.length() - 4, Integer.MAX_VALUE);
292: return sb.toString();
293: }
294:
295: /** Tests whether it shows some content. */
296: public boolean hasContext() {
297: return context != null && context.getRootFiles().size() > 0;
298: }
299: }
|