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 java.io.IOException;
045: import org.netbeans.modules.mercurial.FileInformation;
046: import org.netbeans.modules.mercurial.HgFileNode;
047: import org.netbeans.modules.mercurial.Mercurial;
048: import org.netbeans.modules.mercurial.util.HgUtils;
049: import org.netbeans.modules.mercurial.ui.diff.DiffAction;
050: import org.openide.*;
051: import org.openide.nodes.*;
052: import org.openide.util.*;
053: import org.openide.util.lookup.Lookups;
054: import org.openide.filesystems.FileObject;
055: import org.openide.filesystems.FileUtil;
056: import org.openide.loaders.DataObject;
057: import org.openide.loaders.DataObjectNotFoundException;
058:
059: import javax.swing.*;
060: import java.lang.reflect.InvocationTargetException;
061: import java.io.File;
062: import java.util.logging.Level;
063:
064: /**
065: * The node that is rendered in the SyncTable view. It gets values to display from the
066: * HgFileNode which serves as the 'data' node for this 'visual' node.
067: *
068: * @author Maros Sandor
069: */
070: public class SyncFileNode extends AbstractNode {
071:
072: private HgFileNode node;
073:
074: static final String COLUMN_NAME_NAME = "name"; // NOI18N
075: static final String COLUMN_NAME_PATH = "path"; // NOI18N
076: static final String COLUMN_NAME_STATUS = "status"; // NOI18N
077: static final String COLUMN_NAME_BRANCH = "branch"; // NOI18N
078:
079: private String htmlDisplayName;
080:
081: private RequestProcessor.Task repoload;
082:
083: private final VersioningPanel panel;
084:
085: public SyncFileNode(HgFileNode node, VersioningPanel _panel) {
086: this (Children.LEAF, node, _panel);
087:
088: }
089:
090: private SyncFileNode(Children children, HgFileNode node,
091: VersioningPanel _panel) {
092: super (children, Lookups.fixed(node.getLookupObjects()));
093: this .node = node;
094: this .panel = _panel;
095: initProperties();
096: refreshHtmlDisplayName();
097: }
098:
099: public File getFile() {
100: return node.getFile();
101: }
102:
103: public FileInformation getFileInformation() {
104: return node.getInformation();
105: }
106:
107: public String getName() {
108: return node.getName();
109: }
110:
111: public Action getPreferredAction() {
112: // TODO: getPreferedAction
113: if (node.getInformation().getStatus() == FileInformation.STATUS_VERSIONED_CONFLICT) {
114: return null; //SystemAction.get(ResolveConflictsAction.class);
115: }
116: return new DiffAction(null, HgUtils.getCurrentContext(null));
117: }
118:
119: /**
120: * Provide cookies to actions.
121: * If a node represents primary file of a DataObject
122: * it has respective DataObject cookies.
123: */
124: @SuppressWarnings("unchecked")
125: // Adding getCookie(Class<Cookie> klass) results in name clash
126: public Cookie getCookie(Class klass) {
127: FileObject fo = FileUtil.toFileObject(getFile());
128: if (fo != null) {
129: try {
130: DataObject dobj = DataObject.find(fo);
131: if (fo.equals(dobj.getPrimaryFile())) {
132: return dobj.getCookie(klass);
133: }
134: } catch (DataObjectNotFoundException e) {
135: // ignore file without data objects
136: }
137: }
138: return super .getCookie(klass);
139: }
140:
141: private void initProperties() {
142: if (node.getFile().isDirectory())
143: setIconBaseWithExtension("org/openide/loaders/defaultFolder.gif"); // NOI18N
144:
145: Sheet sheet = Sheet.createDefault();
146: Sheet.Set ps = Sheet.createPropertiesSet();
147:
148: ps.put(new NameProperty());
149: ps.put(new PathProperty());
150: ps.put(new StatusProperty());
151: ps.put(new BranchProperty());
152:
153: sheet.put(ps);
154: setSheet(sheet);
155: }
156:
157: private void refreshHtmlDisplayName() {
158: FileInformation info = node.getInformation();
159: int status = info.getStatus();
160: // Special treatment: Mergeable status should be annotated as Conflict in Versioning view according to UI spec
161: if (status == FileInformation.STATUS_VERSIONED_MERGE) {
162: status = FileInformation.STATUS_VERSIONED_CONFLICT;
163: }
164: htmlDisplayName = Mercurial.getInstance()
165: .getMercurialAnnotator().annotateNameHtml(
166: node.getFile().getName(), info, null);
167: fireDisplayNameChange(node.getName(), node.getName());
168: }
169:
170: public String getHtmlDisplayName() {
171: return htmlDisplayName;
172: }
173:
174: public void refresh() {
175: refreshHtmlDisplayName();
176: }
177:
178: private abstract class SyncFileProperty extends
179: org.openide.nodes.PropertySupport.ReadOnly {
180: @SuppressWarnings("unchecked")
181: protected SyncFileProperty(String name, Class type,
182: String displayName, String shortDescription) {
183: super (name, type, displayName, shortDescription);
184: }
185:
186: public String toString() {
187: try {
188: return getValue().toString();
189: } catch (Exception e) {
190: Mercurial.LOG.log(Level.INFO, null, e);
191: return e.getLocalizedMessage();
192: }
193: }
194: }
195:
196: private class BranchProperty extends SyncFileProperty {
197:
198: public BranchProperty() {
199: super (COLUMN_NAME_BRANCH, String.class, NbBundle
200: .getMessage(SyncFileNode.class, "BK2001"), NbBundle
201: .getMessage(SyncFileNode.class, "BK2002")); // NOI18N
202: }
203:
204: public Object getValue() {
205: String branchInfo = panel.getDisplayBranchInfo();
206: return branchInfo == null ? "" : branchInfo; // NOI18N
207: }
208: }
209:
210: private class PathProperty extends SyncFileProperty {
211:
212: private String shortPath;
213:
214: public PathProperty() {
215: super (COLUMN_NAME_PATH, String.class, NbBundle.getMessage(
216: SyncFileNode.class, "BK2003"), NbBundle.getMessage(
217: SyncFileNode.class, "BK2004")); // NOI18N
218: shortPath = HgUtils.getRelativePath(node.getFile());
219: setValue("sortkey", shortPath + "\t"
220: + SyncFileNode.this .getName()); // NOI18N
221: }
222:
223: public Object getValue() throws IllegalAccessException,
224: InvocationTargetException {
225: return shortPath;
226: }
227: }
228:
229: // XXX it's not probably called, are there another Node lifecycle events
230: public void destroy() throws IOException {
231: super .destroy();
232: if (repoload != null) {
233: repoload.cancel();
234: }
235: }
236:
237: private class NameProperty extends SyncFileProperty {
238:
239: public NameProperty() {
240: super (COLUMN_NAME_NAME, String.class, NbBundle.getMessage(
241: SyncFileNode.class, "BK2005"), NbBundle.getMessage(
242: SyncFileNode.class, "BK2006")); // NOI18N
243: setValue("sortkey", SyncFileNode.this .getName()); // NOI18N
244: }
245:
246: public Object getValue() throws IllegalAccessException,
247: InvocationTargetException {
248: return SyncFileNode.this .getDisplayName();
249: }
250: }
251:
252: private static final String[] zeros = new String[] { "", "00", "0",
253: "" }; // NOI18N
254:
255: private class StatusProperty extends SyncFileProperty {
256:
257: public StatusProperty() {
258: super (COLUMN_NAME_STATUS, String.class, NbBundle
259: .getMessage(SyncFileNode.class, "BK2007"), NbBundle
260: .getMessage(SyncFileNode.class, "BK2008")); // NOI18N
261: String shortPath = HgUtils.getRelativePath(node.getFile()); // NOI18N
262: String sortable = Integer.toString(HgUtils
263: .getComparableStatus(node.getInformation()
264: .getStatus()));
265: setValue("sortkey", zeros[sortable.length()] + sortable
266: + "\t" + shortPath + "\t"
267: + SyncFileNode.this .getName()); // NOI18N
268: }
269:
270: public Object getValue() throws IllegalAccessException,
271: InvocationTargetException {
272: FileInformation finfo = node.getInformation();
273: //TODO: finfo.getEntry(node.getFile()); // XXX not interested in return value, side effect loads ISVNStatus structure
274: int mask = panel.getDisplayStatuses();
275: return finfo.getStatusText(mask);
276: }
277: }
278: }
|