blob: 71c42ae4e9908659ec4b2f40b5d4da693c1f0a01 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.mercurial;
import java.awt.Color;
import java.awt.EventQueue;
import org.openide.util.NbBundle;
import java.io.Serializable;
import java.io.File;
import java.util.*;
import org.netbeans.modules.mercurial.util.HgUtils;
import org.netbeans.modules.versioning.util.common.VCSFileInformation;
/**
* Immutable class encapsulating status of a file.
*
* @author Maros Sandor
*/
public class FileInformation extends VCSFileInformation implements Serializable {
private static final long serialVersionUID = 1L;
/**
* There is nothing known about the file, it may not even exist.
*/
public static final int STATUS_UNKNOWN = 0;
/**
* The file is not managed by the module, i.e. the user does not wish it to be under control of this
* versioning system module. All files except files under versioned roots have this status.
*/
public static final int STATUS_NOTVERSIONED_NOTMANAGED = 1;
/**
* The file exists locally but is NOT under version control because it should not be (i.e. is has
* the Ignore property set or resides under an excluded folder). The file itself IS under a versioned root.
*/
public static final int STATUS_NOTVERSIONED_EXCLUDED = 2;
/**
* The file exists locally but is NOT under version control, mostly because it has not been added
* to the repository yet.
*/
public static final int STATUS_NOTVERSIONED_NEWLOCALLY = 4;
/**
* The file is under version control and is in sync with repository.
*/
public static final int STATUS_VERSIONED_UPTODATE = 8;
/**
* The file is modified locally and was not yet modified in repository.
*/
public static final int STATUS_VERSIONED_MODIFIEDLOCALLY = 16;
/**
* The file was not modified locally but an updated version exists in repository.
*/
public static final int STATUS_VERSIONED_MODIFIEDINREPOSITORY = 32;
/**
* Merging during update resulted in merge conflict. Conflicts in the local copy must be resolved before
* the file can be commited.
*/
public static final int STATUS_VERSIONED_CONFLICT = 64;
/**
* The file was modified both locally and remotely and these changes may or may not result in
* merge conflict.
*/
public static final int STATUS_VERSIONED_MERGE = 128;
/**
* The file does NOT exist locally and exists in repository, it has beed removed locally, waits
* for commit.
*/
public static final int STATUS_VERSIONED_REMOVEDLOCALLY = 256;
/**
* The file does NOT exist locally but exists in repository and has not yet been downloaded.
*/
public static final int STATUS_VERSIONED_NEWINREPOSITORY = 512;
/**
* The file has been removed from repository.
*/
public static final int STATUS_VERSIONED_REMOVEDINREPOSITORY = 1024;
/**
* The file does NOT exist locally and exists in repository, it has beed removed locally.
*/
public static final int STATUS_VERSIONED_DELETEDLOCALLY = 2048;
/**
* The file exists locally and has beed scheduled for addition to repository. This status represents
* state after the 'add' command.
*/
public static final int STATUS_VERSIONED_ADDEDLOCALLY = 4096;
public static final int STATUS_ALL = ~0;
/**
* All statuses except <tt>STATUS_NOTVERSIONED_NOTMANAGED</tt>
*
* <p>Note: it covers ignored files.
*/
public static final int STATUS_MANAGED = FileInformation.STATUS_ALL & ~FileInformation.STATUS_NOTVERSIONED_NOTMANAGED;
public static final int STATUS_VERSIONED = FileInformation.STATUS_VERSIONED_UPTODATE |
FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY |
FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY |
FileInformation.STATUS_VERSIONED_CONFLICT |
FileInformation.STATUS_VERSIONED_MERGE |
FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY |
FileInformation.STATUS_VERSIONED_REMOVEDINREPOSITORY |
FileInformation.STATUS_VERSIONED_DELETEDLOCALLY |
FileInformation.STATUS_VERSIONED_ADDEDLOCALLY;
public static final int STATUS_IN_REPOSITORY = FileInformation.STATUS_VERSIONED_UPTODATE |
FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY |
FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY |
FileInformation.STATUS_VERSIONED_CONFLICT |
FileInformation.STATUS_VERSIONED_MERGE |
FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY |
FileInformation.STATUS_VERSIONED_NEWINREPOSITORY |
FileInformation.STATUS_VERSIONED_REMOVEDINREPOSITORY |
FileInformation.STATUS_VERSIONED_DELETEDLOCALLY;
public static final int STATUS_LOCAL_CHANGE =
FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY |
FileInformation.STATUS_VERSIONED_ADDEDLOCALLY |
FileInformation.STATUS_VERSIONED_CONFLICT |
FileInformation.STATUS_VERSIONED_DELETEDLOCALLY |
FileInformation.STATUS_VERSIONED_MERGE |
FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY |
FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY;
/**
* Modified, in conflict, scheduled for removal or addition;
* or deleted but with existing entry record.
*/
public static final int STATUS_REVERTIBLE_CHANGE =
FileInformation.STATUS_VERSIONED_ADDEDLOCALLY |
FileInformation.STATUS_VERSIONED_CONFLICT |
FileInformation.STATUS_VERSIONED_MERGE |
FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY |
FileInformation.STATUS_VERSIONED_DELETEDLOCALLY |
FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY;
public static final int STATUS_REMOTE_CHANGE =
FileInformation.STATUS_VERSIONED_MERGE |
FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY |
FileInformation.STATUS_VERSIONED_NEWINREPOSITORY |
FileInformation.STATUS_VERSIONED_REMOVEDINREPOSITORY;
private static final int STATUS_VERSIONED_REMOVED =
FileInformation.STATUS_VERSIONED_DELETEDLOCALLY |
FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY;
/**
* Status constant.
*/
private final int status;
/**
* More detailed information about a file, you may disregard the field if not needed.
*/
private transient FileStatus entry;
/**
* Directory indicator, mainly because of files that may have been deleted so file.isDirectory() won't work.
*/
private final boolean isDirectory;
private final HashSet<File> modifiedChildren = new HashSet<File>();
private final HashSet<File> conflictedChildren = new HashSet<File>();
private boolean seenInUI;
/**
* For deserialization purposes only.
*/
public FileInformation() {
status = 0;
isDirectory = false;
}
public FileInformation(int status, FileStatus entry, boolean isDirectory) {
this.status = status;
this.entry = entry;
this.isDirectory = isDirectory;
this.seenInUI = !isDirectory; // files are always marked as seen
}
FileInformation(int status, boolean isDirectory) {
this(status, null, isDirectory);
}
/**
* Retrieves the status constant representing status of the file.
*
* @return one of status constants
*/
public int getStatus() {
return status;
}
public boolean isDirectory() {
return isDirectory;
}
/**
* Retrieves file's Status.
*
* @param file file this information belongs to or null if you do not want the entry to be read from disk
* in case it is not loaded yet
* @return Status parsed entry form the .svn/entries file or null if the file does not exist,
* is not versioned or its entry is invalid
*/
public FileStatus getStatus(File file) {
return entry;
}
/**
* Returns localized text representation of status.
*
* @return status name, for multistatuses prefers local
* status name.
*/
@Override
public String getStatusText() {
return getStatusText(~0);
}
/**
* Returns localized text representation of status.
*
* @param displayStatuses statuses bitmask
*
* @return status name, for multistatuses prefers local
* status name, for masked <tt>""</tt>. // NOI18N
*/
public String getStatusText(int displayStatuses) {
int status = this.status & displayStatuses;
ResourceBundle loc = NbBundle.getBundle(FileInformation.class);
if (status == FileInformation.STATUS_UNKNOWN) {
return loc.getString("CTL_FileInfoStatus_Unknown"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_NOTVERSIONED_EXCLUDED)) {
return loc.getString("CTL_FileInfoStatus_Excluded"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_NewLocally"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_ADDEDLOCALLY)) {
if (entry != null && entry.isCopied()) {
if (!EventQueue.isDispatchThread() && !entry.getOriginalFile().exists()
|| (Mercurial.getInstance().getFileStatusCache().getStatus(entry.getOriginalFile()).getStatus()
& FileInformation.STATUS_VERSIONED_REMOVED) != 0) {
if (entry.getOriginalFile().getParentFile().getAbsolutePath()
.equals(entry.getFile().getParentFile().getAbsolutePath())) {
return loc.getString("CTL_FileInfoStatus_AddedLocallyRenamed"); // NOI18N
} else {
return loc.getString("CTL_FileInfoStatus_AddedLocallyMoved"); // NOI18N
}
} else {
return loc.getString("CTL_FileInfoStatus_AddedLocallyCopied"); // NOI18N
}
}
return loc.getString("CTL_FileInfoStatus_AddedLocally"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_UPTODATE)) {
return loc.getString("CTL_FileInfoStatus_UpToDate"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_CONFLICT)) {
return loc.getString("CTL_FileInfoStatus_Conflict"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_MERGE)) {
return loc.getString("CTL_FileInfoStatus_Merge"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_DELETEDLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_DeletedLocally"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_RemovedLocally"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_ModifiedLocally"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_NEWINREPOSITORY)) {
return loc.getString("CTL_FileInfoStatus_NewInRepository"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY)) {
return loc.getString("CTL_FileInfoStatus_ModifiedInRepository"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_REMOVEDINREPOSITORY)) {
return loc.getString("CTL_FileInfoStatus_RemovedInRepository"); // NOI18N
} else {
return ""; // NOI18N
}
}
/**
* @return short status name for local changes, for remote
* changes returns <tt>""</tt> // NOI18N
*/
public String getShortStatusText() {
ResourceBundle loc = NbBundle.getBundle(FileInformation.class);
if (FileInformation.match(status, FileInformation.STATUS_NOTVERSIONED_EXCLUDED)) {
return loc.getString("CTL_FileInfoStatus_Excluded_Short"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_NewLocally_Short"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_ADDEDLOCALLY)) {
if (entry != null && entry.isCopied()) {
if (!EventQueue.isDispatchThread() && !entry.getOriginalFile().exists()
|| (Mercurial.getInstance().getFileStatusCache().getStatus(entry.getOriginalFile()).getStatus()
& FileInformation.STATUS_VERSIONED_REMOVED) != 0) {
if (entry.getOriginalFile().getParentFile().getAbsolutePath()
.equals(entry.getFile().getParentFile().getAbsolutePath())) {
return loc.getString("CTL_FileInfoStatus_AddedLocallyRenamed_Short"); //NOI18N
} else {
return loc.getString("CTL_FileInfoStatus_AddedLocallyMoved_Short"); //NOI18N
}
} else {
return loc.getString("CTL_FileInfoStatus_AddedLocallyCopied_Short"); //NOI18N
}
}
return loc.getString("CTL_FileInfoStatus_AddedLocally_Short"); // NOI18N
} else if (status == FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY) {
return loc.getString("CTL_FileInfoStatus_RemovedLocally_Short"); // NOI18N
} else if (status == FileInformation.STATUS_VERSIONED_DELETEDLOCALLY) {
return loc.getString("CTL_FileInfoStatus_DeletedLocally_Short"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY)) {
return loc.getString("CTL_FileInfoStatus_ModifiedLocally_Short"); // NOI18N
} else if (FileInformation.match(status, FileInformation.STATUS_VERSIONED_CONFLICT)) {
return loc.getString("CTL_FileInfoStatus_Conflict_Short"); // NOI18N
} else {
return ""; // NOI18N
}
}
private static boolean match(int status, int mask) {
return (status & mask) != 0;
}
@Override
public String toString() {
return "Text: " + status + " " + getStatusText(status); // NOI18N
}
HashSet<File> getModifiedChildren (boolean onlyConflicted) {
HashSet<File> children;
synchronized (modifiedChildren) {
if (onlyConflicted) {
children = new HashSet<File>(conflictedChildren);
} else {
children = new HashSet<File>(modifiedChildren);
}
}
return children;
}
boolean setModifiedChild (File child, FileInformation newInfo) {
if ((status & STATUS_NOTVERSIONED_NOTMANAGED) != 0) {
return false;
}
synchronized (modifiedChildren) {
modifiedChildren.remove(child);
conflictedChildren.remove(child);
boolean followOnParent = modifiedChildren.isEmpty(); // information may be only removed, notify parent if this folder has no modified children
if (newInfo.getStatus() != STATUS_UNKNOWN && (newInfo.getStatus() & STATUS_VERSIONED_UPTODATE) == 0) {
boolean testBeforeAdd = false;
assert testBeforeAdd = true;
if (testBeforeAdd && modifiedChildren.size() > 0) {
File alreadyAdded = modifiedChildren.iterator().next();
if (!child.getParentFile().equals(alreadyAdded.getParentFile())) {
throw new IllegalStateException("Adding " + child.getAbsolutePath() + ", already added " //NOI18N
+ alreadyAdded.getAbsolutePath() + " under " //NOI18N
+ alreadyAdded.getParentFile().getAbsolutePath());
}
}
modifiedChildren.add(child);
if ((newInfo.getStatus() & STATUS_VERSIONED_CONFLICT) != 0) {
conflictedChildren.add(child);
}
followOnParent = true; // information was added, notify the parent
}
return followOnParent;
}
}
/**
* Returns value of the flag indicating if the file associated with this FI is/was visible in the UI
* @return
*/
boolean wasSeenInUi () {
return seenInUI;
}
/**
* Sets value of the flag indicating if the file associated with this FI is/was visible in the UI
* @param seenInUI
*/
void setSeenInUI (boolean seenInUI) {
this.seenInUI = seenInUI;
}
@Override
public int getComparableStatus () {
return HgUtils.getComparableStatus(status);
}
@Override
public String annotateNameHtml (String name) {
return Mercurial.getInstance().getMercurialAnnotator().annotateNameHtml(name, this, null);
}
@Override
public Color getAnnotatedColor () {
return Mercurial.getInstance().getMercurialAnnotator().getAnnotatedColor(this);
}
}