36568: CVS tag property shows "(branch)" and "(version)" for same project
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java
index 2a19f16..1191486 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java
@@ -18,15 +18,23 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.team.internal.ccvs.core.CVSException;
 import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
+import org.eclipse.team.internal.ccvs.core.CVSTag;
 import org.eclipse.team.internal.ccvs.core.ICVSFolder;
 import org.eclipse.team.internal.ccvs.core.ICVSResource;
 import org.eclipse.team.internal.ccvs.core.Policy;
 import org.eclipse.team.internal.ccvs.core.client.Session;
+import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
+import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
 
 /**
  * Unsorted static helper-methods 
@@ -328,4 +336,108 @@
 		}
 		return true;
 	}
+	
+	/**
+	 * Workaround a CVS bug where a CVS Folder with no immediately contained files has an incorrect
+	 * Tag type stored in the TAG file.  In this case, the tag type is always BRANCH (Tv1)
+	 * 
+	 * The fix is for folders with no files, use the tag type for the containing project.  Since projects almost
+	 * always have files the TAG file is usually correct.
+	 * 
+	 * For the case where the folder tag name does not match the project tag name we can not do much so we just
+	 * return the folder tag which will currently always be a branch.
+	 * 
+	 * @param resource The IResource being tested.  Can not be null.
+	 * @param tag The CVSTag as reported by CVS for the IResource.  May be null.
+	 * @return CVSTag The corrected tag for the resource.  May be null.
+	 */
+	
+	public static CVSTag getAccurateFolderTag(IResource resource, CVSTag tag) {
+
+		// Determine if the folder contains files as immediate children.
+		if (resource.getType() != IResource.FOLDER) {
+			return tag;
+		}
+
+		IResource[] members = null;
+		try {
+			members = ((IFolder) resource).members();
+		} catch (CoreException e1) {
+			return tag;
+		}
+		
+		for (int i = 0; i < members.length; i++) {
+			if (members[i].getType() == IResource.FILE) {
+				return tag;
+			}
+		}
+	
+		// Folder contains no files so this may not really be a branch.
+		// Make the type the same as the project tag type if both are the same tag name.
+		IProject project = resource.getProject();
+		if (project == null) {
+			return tag;
+		}
+		
+		ICVSFolder projectFolder = CVSWorkspaceRoot.getCVSFolderFor(project);
+		FolderSyncInfo projectSyncInfo;
+		try {
+			projectSyncInfo = projectFolder.getFolderSyncInfo();
+		} catch (CVSException e) {
+			return tag;
+		}
+		
+		if (projectSyncInfo == null) {
+			return tag;
+		}
+		
+		CVSTag projectTag = projectSyncInfo.getTag();
+								
+		if (projectTag != null && projectTag.getName().equals(tag.getName())) {
+			return projectTag;
+		} else {
+			return tag;
+		}
+	}	
+	
+	/**
+	 * Workaround for CVS "bug" where CVS ENTRIES file does not contain correct
+	 * Branch vs. Version info.  Entries files always record a Tv1 so all entries would
+	 * appear as branches.
+	 * 	
+	 * By comparing the revision number to the tag name
+	 * you can determine if the tag is a branch or version.
+	 * 
+	 * @param cvsResource the resource to test.  Must nut be null.
+	 * @return the correct cVSTag.  May be null.
+	 */
+	
+	public static CVSTag getAccurateFileTag(ICVSResource cvsResource) throws CVSException {
+
+		CVSTag tag = null;
+		ResourceSyncInfo info = cvsResource.getSyncInfo();
+		if(info != null) {
+			tag = info.getTag();
+		}
+
+		FolderSyncInfo parentInfo = cvsResource.getParent().getFolderSyncInfo();
+		CVSTag parentTag = null;
+		if(parentInfo != null) {
+			parentTag = parentInfo.getTag();
+		}
+
+		if(tag != null) {
+			if(tag.getName().equals(info.getRevision())) {
+				tag = new CVSTag(tag.getName(), CVSTag.VERSION);
+			} else if(parentTag != null && tag.getName().equals(parentTag.getName())){
+				tag = new CVSTag(tag.getName(), parentTag.getType());
+			}
+		} else {
+			// if a file doesn't have tag info, very possible for example
+			// when the file is in HEAD, use the parents.
+			tag = parentTag;
+		}
+		
+		return tag;						
+	}
 }
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java
index a9411ab..0c6fd90 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java
@@ -27,10 +27,10 @@
 import org.eclipse.team.internal.ccvs.core.ICVSFile;
 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
-import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.team.internal.ccvs.core.util.Util;
 import org.eclipse.ui.help.WorkbenchHelp;
 
-public class CVSFilePropertiesPage extends PropertyPage {
+public class CVSFilePropertiesPage extends CVSPropertiesPage {
 	IFile file;
 
 	/*
@@ -83,14 +83,8 @@
 			
 			// Tag
 			createLabel(composite, Policy.bind("CVSFilePropertiesPage.tag")); //$NON-NLS-1$
-			CVSTag tag = syncInfo.getTag();
-			if (tag == null) {
-				createLabel(composite, Policy.bind("CVSFilePropertiesPage.none")); //$NON-NLS-1$
-			} else {
-				// In an entry file we can't differentiate branch and version tags. They both appear
-				// as T<tagName>. Instead just display the tag name to the user.
-				createLabel(composite, tag.getName());
-			}
+			CVSTag tag = Util.getAccurateFileTag(cvsResource);
+			createLabel(composite, getTagLabel(tag));
 			
 			// Permissions
 			createLabel(composite, Policy.bind("CVSFilePropertiesPage.permissions")); //$NON-NLS-1$
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFolderPropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFolderPropertiesPage.java
index c75c8c7..3f37314 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFolderPropertiesPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFolderPropertiesPage.java
@@ -29,10 +29,10 @@
 import org.eclipse.team.internal.ccvs.core.ICVSFolder;
 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
-import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.team.internal.ccvs.core.util.Util;
 import org.eclipse.ui.help.WorkbenchHelp;
 
-public class CVSFolderPropertiesPage extends PropertyPage {
+public class CVSFolderPropertiesPage extends CVSPropertiesPage {
 
 	IFolder folder;
 	private Label root;
@@ -72,15 +72,12 @@
 				// Tag
 				createLabel(composite, Policy.bind("CVSFilePropertiesPage.tag")); //$NON-NLS-1$
 				CVSTag tag = syncInfo.getTag();
-				if (tag == null) {
-					createLabel(composite, Policy.bind("CVSFilePropertiesPage.none")); //$NON-NLS-1$
-				} else {
-					if (tag.getType() == CVSTag.DATE) {
-						createLabel(composite, Policy.bind("CVSFilePropertiesPage.date", tag.getName())); //$NON-NLS-1$
-					} else {
-						createLabel(composite, tag.getName());
-					}
+
+				if (tag != null && tag.getType() == CVSTag.BRANCH) {
+					tag = Util.getAccurateFolderTag(folder, tag);				
 				}
+			
+				createLabel(composite, getTagLabel(tag));
 				
 				// Static-ness
 				if (syncInfo.getIsStatic()) {
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSProjectPropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSProjectPropertiesPage.java
index 2819e88..cef9cf7 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSProjectPropertiesPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSProjectPropertiesPage.java
@@ -51,12 +51,11 @@
 import org.eclipse.team.internal.ccvs.core.IUserInfo;
 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
-import org.eclipse.ui.dialogs.PropertyPage;
 import org.eclipse.ui.help.WorkbenchHelp;
 import org.eclipse.ui.model.WorkbenchContentProvider;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
 
-public class CVSProjectPropertiesPage extends PropertyPage {
+public class CVSProjectPropertiesPage extends CVSPropertiesPage {
 	IProject project;
 	ICVSRepositoryLocation oldLocation;
 	ICVSRepositoryLocation newLocation = null;
@@ -346,13 +345,9 @@
 		try {
 			ICVSFolder local = CVSWorkspaceRoot.getCVSFolderFor(project);
 			CVSTag tag = local.getFolderSyncInfo().getTag();
-			String tagName;
-			if (tag == null) {
-				tagName = Policy.bind("CVSFilePropertiesPage.none");
-			} else {
-				tagName = tag.getName();
-			}
-			tagLabel.setText(tagName);
+			
+			tagLabel.setText(getTagLabel(tag));
+
 		} catch (TeamException e) {
 			handle(e);
 		}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java
new file mode 100644
index 0000000..c58aa8e
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSPropertiesPage.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.internal.ccvs.ui;
+
+import org.eclipse.team.internal.ccvs.core.CVSTag;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+public abstract class CVSPropertiesPage extends PropertyPage {
+
+	/**
+	 * Return the appropriate Tag label for properties pages
+	 * based on the tag type.
+	 * @param tag
+	 * @return String
+	 */
+	
+	public static String getTagLabel(CVSTag tag) {
+	
+		if (tag == null) {
+			return Policy.bind("CVSFilePropertiesPage.none"); //$NON-NLS-1$
+		}
+		
+		switch (tag.getType()) {
+			case CVSTag.HEAD:
+				return tag.getName();
+			case CVSTag.VERSION:
+				return Policy.bind("CVSFilePropertiesPage.version", tag.getName()); //$NON-NLS-1$
+			case CVSTag.BRANCH:
+				return Policy.bind("CVSFilePropertiesPage.branch", tag.getName()); //$NON-NLS-1$
+			case CVSTag.DATE:
+				return Policy.bind("CVSFilePropertiesPage.date", tag.getName()); //$NON-NLS-1$
+			default :
+				return tag.getName();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/WorkspaceAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/WorkspaceAction.java
index e43f0ab..99180fb 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/WorkspaceAction.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/WorkspaceAction.java
@@ -45,6 +45,7 @@
 import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
+import org.eclipse.team.internal.ccvs.core.util.Util;
 import org.eclipse.team.internal.ccvs.ui.Policy;
 import org.eclipse.team.internal.ui.IPromptCondition;
 import org.eclipse.team.internal.ui.PromptingDialog;
@@ -453,31 +454,11 @@
 					if(info != null) {
 						tag = info.getTag();									
 					}
+					if (tag != null && tag.getType() == CVSTag.BRANCH) {
+						tag = Util.getAccurateFolderTag(resources[i], tag);
+					}
 				} else {
-					ResourceSyncInfo info = cvsResource.getSyncInfo();
-					if(info != null) {
-						tag = info.getTag();
-					}
-					// This magic is required because of a bug in CVS which doesn't store the
-					// type of tag for files correctly in the Entries file. They will always appear
-					// as branch tags "Tv1". By comparing the revision number to the tag name
-					// you can determine if the tag is a branch or version.
-					FolderSyncInfo parentInfo = cvsResource.getParent().getFolderSyncInfo();
-					CVSTag parentTag = null;
-					if(parentInfo != null) {
-						parentTag = parentInfo.getTag();
-					}
-					if(tag != null) {
-						if(tag.getName().equals(info.getRevision())) {
-							tag = new CVSTag(tag.getName(), CVSTag.VERSION);
-						} else if(parentTag != null){
-							tag = new CVSTag(tag.getName(), parentTag.getType());
-						}
-					} else {
-						// if a file doesn't have tag info, very possible for example
-						// when the file is in HEAD, use the parents.
-						tag = parentTag;
-					}
+					tag = Util.getAccurateFileTag(cvsResource);
 				}
 				if(tag == null) {
 					tag = new CVSTag();
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties
index 47dd531..554b4f1 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties
@@ -146,7 +146,9 @@
 CVSFilePropertiesPage.modified=Modified:
 CVSFilePropertiesPage.keywordMode=Keyword mode:
 CVSFilePropertiesPage.tag=Tag:
-CVSFilePropertiesPage.none=(none)
+CVSFilePropertiesPage.none=HEAD
+CVSFilePropertiesPage.version={0} (Version)
+CVSFilePropertiesPage.branch={0} (Branch)
 CVSFilePropertiesPage.date={0} (Date)
 CVSFilePropertiesPage.error=An error occurred while creating this page.
 CVSFilePropertiesPage.permissions=Permissions: