package com.atlassian.uwc.ui; | |
import java.io.File; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Set; | |
import java.util.Vector; | |
/** | |
* A class representing a wiki page that is being converted to Confluence. | |
* This holds the meta data needed to convert a Page. | |
* | |
* User: Rex (Rolf Staflin) | |
* Date: 2006-94-05 | |
* Time: 15:40:25 | |
*/ | |
public class Page implements Comparable { | |
/** | |
* File the page represents | |
*/ | |
private File file; | |
/** | |
* text that the page has before each conversion | |
*/ | |
private String originalText; | |
/** | |
* original source text. This should never be changed once | |
* it is set. Note: This is different from originalText in that | |
* originalText will be updated to reflect the most current | |
* text at the beginning of each syntax conversion. | |
*/ | |
private String unchangedSource; | |
/** | |
* text that the page has after the conversion | |
*/ | |
private String convertedText; | |
/** | |
* page name. Will be used by Confluence when the page is created in Confluence. | |
*/ | |
private String name; | |
/** | |
* filepath to the page | |
*/ | |
private String path; | |
/** | |
* set of attachments associated with this page | |
*/ | |
private Set<Attachment> attachments; | |
/** | |
* page version, used by the UWC Page History Framework. | |
* @see http://confluence.atlassian.com/display/CONFEXT/UWC+Page+History+Framework | |
*/ | |
private int version = 1; //the default is 1 | |
/** | |
* set of labels associated with this page | |
*/ | |
private Set<String> labels; | |
/** | |
* list of page comments associated with this page | |
* NOTE: At this time, we're only passing in the comment contents, | |
* as all other comment parameters either (a) can't be set with | |
* the remote api or (b) will not need to be assocated seperately (page id) | |
*/ | |
private Vector<Comment> comments; //It's a vector instead of a set to preserver order | |
/** | |
* username of author who updated this page. If null, the administrator running the UWC will be used | |
*/ | |
private String author; | |
/** | |
* timestamp when the author updated this page. | |
*/ | |
private Date timestamp; | |
/** | |
* map providing information about which version is the latest for a given title. | |
* There should only be data in this object if pages have been sorted by history in the ConverterEngine | |
*/ | |
private static HashMap<String, Integer> latestVersions = new HashMap<String, Integer>(); | |
/** | |
* Optionally associate the page with a spacekey. The ConverterEngine will use this instead of the spacekey setting. | |
*/ | |
private String spacekey; | |
/** | |
* keep needed space data here so the ConverterEngine can create the space, if necessary | |
* The key is the spacekey. The value is an array with name and description data in the 0th and 1st indexes, | |
* respectively. The name and description data will only be used if the spacekey is not already in use, and | |
* therefore a space needs to be created. | |
*/ | |
private static HashMap<String,String[]> spaces = new HashMap<String, String[]>(); //spacekey -> [name, description] | |
private boolean isBlog = false; | |
private boolean isPersonalSpace = false; | |
private String personalSpaceUsername = null; | |
/** | |
* If the page history framework is using the load-as-ancestors properties, then we load the ancestor versions of | |
* the page into this object. Useful for interacting more easily with existing hierarchies. | |
*/ | |
private Vector<VersionPage> ancestors; | |
/** | |
* confluence entity id. useful for updating blogs. | |
*/ | |
private String id; | |
/** | |
* set by the engine, used by the compareTo method | |
*/ | |
private boolean sortWithTimestamp = false; | |
/** | |
* Basic constructor. Creates a page with an empty path. | |
* @param file The file to be converted. | |
*/ | |
public Page(File file) { | |
init(file, ""); | |
} | |
/** | |
* Basic constructor. | |
* @param file The file to be converted. | |
* @param path A path used to construct a page hierarchy for | |
* some wikis. | |
*/ | |
public Page(File file, String path) { | |
init(file, path); | |
} | |
/** | |
* initializes the page | |
* @param file | |
* @param path | |
*/ | |
private void init(File file, String path) { | |
this.file = file; | |
attachments = new HashSet<Attachment>(); | |
labels = new HashSet<String>(); | |
comments = new Vector<Comment>(); | |
setPath(path); | |
} | |
/** | |
* used when sorting pages. | |
* Takes into account page name and page version | |
* @see java.lang.Comparable#compareTo(java.lang.Object) | |
*/ | |
public int compareTo(Object o) { | |
Page b = (Page) o; | |
int versionA = this.version; | |
int versionB = b.getVersion(); | |
String nameA = this.name; | |
String nameB = b.getName(); | |
//make sure there's a default value so we don't get NPE | |
if (nameA == null) nameA = ""; | |
if (nameB == null) nameB = ""; | |
//order by name - if name is the same, in order by version | |
int compareValue = (nameA.compareTo(nameB)); | |
if (compareValue == 0) { | |
if (!sortWithTimestamp) compareValue = versionA - versionB; | |
} | |
return compareValue; | |
} | |
/** | |
* Adds a single attachment to the page. If the attachment was already | |
* added (e.g., an image that appears several times on the page) it is not added again. | |
* @param newAttachment The file to be attached to the page. It must not be null. | |
*/ | |
public void addAttachment(File newAttachment) { | |
assert newAttachment != null; | |
attachments.add(new Attachment(newAttachment)); | |
} | |
public void addAttachment(File attachment, String name) { | |
attachments.add(new Attachment(attachment, name)); | |
} | |
public void addAttachment(Attachment attachment) { | |
attachments.add(attachment); | |
} | |
/* Getters and Setters */ | |
public File getFile() { | |
return file; | |
} | |
public String getOriginalText() { | |
return originalText; | |
} | |
public void setOriginalText(String originalText) { | |
this.originalText = originalText; | |
} | |
public String getUnchangedSource() { | |
return unchangedSource; | |
} | |
/** | |
* sets the unchangedSource field. Cannot be set more than once. | |
* @throws IllegalStateException if the source has already been set. | |
*/ | |
public void setUnchangedSource(String unchangedSource) { | |
if (this.unchangedSource != null) | |
throw new IllegalStateException("Source Text has already been set. It may not be changed further."); | |
this.unchangedSource = unchangedSource; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
/** | |
* Returns the relative path of the page. This path is constructed by ConverterEngine.recurse(). | |
* Top-level (root) pages have an empty path, while other pages have paths with the elements | |
* separated by <code>File.separator</code>, e.g. "/path/to/the/page.txt" on unix systems and | |
* "\path\to\the\page.txt" on Windows systems. | |
* | |
* @return The path of the page. | |
*/ | |
public String getPath() { | |
return path; | |
} | |
public void setPath(String path) { | |
this.path = path; | |
} | |
public String getConvertedText() { | |
return convertedText; | |
} | |
public void setConvertedText(String convertedText) { | |
this.convertedText = convertedText; | |
} | |
public Set<File> getAttachments() { | |
HashSet<File> justFiles = new HashSet<File>(); | |
for (Attachment att : this.attachments) { | |
justFiles.add(att.getFile()); | |
} | |
return justFiles; | |
} | |
public void setAttachments(Set<File> attachments) { | |
assert attachments != null; | |
this.attachments.clear(); | |
for (File file : attachments) { | |
this.attachments.add(new Attachment(file)); | |
} | |
} | |
public Set<Attachment> getAllAttachmentData() { | |
return this.attachments; | |
} | |
public void setVersion(int version) { | |
//save latest version data | |
if (getLatestVersion(getName()) <= version) { | |
latestVersions.put(getName(), version); | |
} | |
this.version = version; | |
} | |
public int getVersion() { | |
return this.version; | |
} | |
/** | |
* @return map of title -> latest version data. | |
*/ | |
public static HashMap<String, Integer> getLatestVersions() { | |
return latestVersions; | |
} | |
/** | |
* Latest version data is noted when setVersion is called based on the name the object has | |
* when setVersion is called. | |
* @param name page name this version is associated with | |
* @return latest version for title or 1 if no version set yet | |
*/ | |
public static int getLatestVersion(String name) { | |
Integer latest = getLatestVersions().get(name); | |
if (latest == null) return 1; | |
return latest; | |
} | |
public int getLatestVersion() { | |
return getLatestVersion(getName()); | |
} | |
public Set<String> getLabels() { | |
return labels; | |
} | |
public void setLabels(Set<String> labels) { | |
this.labels = labels; | |
} | |
/** | |
* @return set of labels as a comma delimited list. null if | |
* labels is null or empty | |
*/ | |
public String getLabelsAsString() { | |
if (this.labels == null) return null; | |
if (this.labels.isEmpty()) return null; | |
boolean first = true; | |
String labelString = ""; | |
for (String label : this.labels) { | |
if (first) first = false; | |
else labelString += ", "; | |
labelString += label; | |
} | |
return labelString; | |
} | |
/** | |
* adds the given label to the set of labels associated with this page, | |
* removes disallowed confluence label chars, | |
* and toLowerCases the label to: (a) avoid remote api errors and | |
* (b) better represent what the results of uploading a given label to Confluence will be. | |
* If you don't want the labels to be processed, use the setLabels method instead. | |
* @param label | |
*/ | |
public void addLabel(String label) { | |
label = label.trim(); | |
label = label.replaceAll("[ !#&()*,.:;<>?@\\[\\]\\^]", ""); //remove disallowed confluence tag chars | |
label = label.toLowerCase(); | |
this.labels.add(label); | |
} | |
public Vector<String> getComments() { | |
Vector<String> commentStrings = new Vector<String>(); | |
for (Comment comment : this.comments) { | |
commentStrings.add(comment.text); | |
} | |
return commentStrings; | |
} | |
public Vector<Comment> getAllCommentData() { | |
return this.comments; | |
} | |
public void setComments(Vector <String> comments) { | |
for (String comment : comments) { | |
this.comments.add(new Comment(comment)); | |
} | |
} | |
public void addComment(String comment) { | |
this.comments.add(new Comment(comment)); | |
} | |
public void addComment(Comment comment) { | |
this.comments.add(comment); | |
} | |
public void addComment(String comment, String creator, String date) { | |
this.comments.add(new Comment(comment, creator, date)); | |
} | |
public boolean hasComments() { | |
return !this.comments.isEmpty(); | |
} | |
public String getAuthor() { | |
return author; | |
} | |
public void setAuthor(String author) { | |
this.author = author; | |
} | |
public Date getTimestamp() { | |
return timestamp; | |
} | |
public void setTimestamp(Date timestamp) { | |
this.timestamp = timestamp; | |
} | |
/* Space methods */ | |
public String getSpacekey() { | |
return spacekey; | |
} | |
public void setSpacekey(String key) { | |
this.spacekey = key; | |
} | |
/** | |
* sets the spacekey for this page, and also assigns name and description data | |
* to a map so that if the space needs to be created, we have that information. | |
* @param key | |
* @param name | |
* @param desc | |
*/ | |
public void setSpace(String key, String name, String desc) { | |
setSpacekey(key); | |
String[] newdata = {name, desc}; | |
this.spaces.put(key, newdata); | |
} | |
/** | |
* gets the space data that's been saved for a particular spacekey, or null if no data exists for that key | |
* @param key | |
* @return array. 0th index is the name of the space, 1st index is the description | |
*/ | |
public String[] getSpaceData(String key) { | |
if (spaces.containsKey(key)) return spaces.get(key); | |
return null; | |
} | |
/** | |
* true if the spaces data map has an entry for the given key | |
* @param key | |
* @return | |
*/ | |
public boolean hasSpace(String key) { | |
return spaces.containsKey(key); | |
} | |
public boolean isBlog() { | |
return isBlog; | |
} | |
public void setIsBlog(boolean isBlog) { | |
this.isBlog = isBlog; | |
} | |
public boolean isPersonalSpace() { | |
return isPersonalSpace; | |
} | |
public void setIsPersonalSpace(boolean isPersonalSpace) { | |
this.isPersonalSpace = isPersonalSpace; | |
} | |
public String getPersonalSpaceUsername() { | |
return this.personalSpaceUsername; | |
} | |
public void setPersonalSpaceUsername(String username) { | |
this.personalSpaceUsername = username; | |
} | |
public void addAncestor(VersionPage ancestor) { | |
getAncestors().add(ancestor); | |
} | |
public Vector<VersionPage> getAncestors() { | |
if (this.ancestors == null) | |
this.ancestors = new Vector<VersionPage>(); | |
return this.ancestors; | |
} | |
public void setParent(Page page) { | |
throw new IllegalStateException("Use VersionPage if you wish to set the parent."); | |
} | |
public Page getParent() { | |
return null; | |
} | |
public boolean sameTimestampAndContent(Page page) { | |
boolean content = (this.getConvertedText() != null | |
&& this.getConvertedText().equals(page.getConvertedText())); | |
boolean timeisnull = (this.getTimestamp() == null && page.getTimestamp() == null); | |
boolean time = (this.getTimestamp() != null | |
&& page.getTimestamp() != null | |
&& this.getTimestamp().getTime() == page.getTimestamp().getTime()); | |
return content && (timeisnull || time); | |
} | |
public String getId() { | |
return id; | |
} | |
public void setId(String id) { | |
this.id = id; | |
} | |
public boolean isSortWithTimestamp() { | |
return sortWithTimestamp; | |
} | |
public void setSortWithTimestamp(boolean sortWithTimestamp) { | |
this.sortWithTimestamp = sortWithTimestamp; | |
} | |
} |