📄 pagesstorageprovider.cs
字号:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
namespace ScrewTurn.Wiki {
/// <summary>
/// Implements a Pages Storage Provider.
/// </summary>
[Serializable]
public class PagesStorageProvider : IPagesStorageProvider {
/// <summary>
/// Used as lock object for multithreaded operations.
/// </summary>
private object locker = new object();
private object lockerDisc = new object();
private ComponentInformation info = new ComponentInformation("Local Pages Provider", "ScrewTurn Software", "http://www.screwturn.eu");
private IHost host;
/// <summary>
/// Initializes the Provider.
/// </summary>
/// <param name="host">The Host of the Provider.</param>
/// <param name="config">The Configuration data, if any.</param>
public void Init(IHost host, string config) {
this.host = host;
}
/// <summary>
/// Method invoked on shutdown.
/// </summary>
/// <remarks>This method might not be invoked in some cases.</remarks>
public void Shutdown() { }
/// <summary>
/// Gets the Information about the Provider.
/// </summary>
public ComponentInformation Information {
get { return info; }
}
/// <summary>
/// Gets a value specifying whether the provider is read-only, i.e. it can only provide data and not store it.
/// </summary>
public bool ReadOnly {
get { return false; }
}
/// <summary>
/// Gets all the Pages.
/// </summary>
/// <remarks>The array is unsorted.</remarks>
public PageInfo[] AllPages {
get {
string tmp;
lock(locker) {
tmp = Tools.LoadFile(Settings.PagesFile).Replace("\r", "");
}
string[] lines = tmp.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
PageInfo[] result = new PageInfo[lines.Length];
string[] fields;
for(int i = 0; i < lines.Length; i++) {
fields = lines[i].Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
// Structure
// PageName|PageFile|Status(optional);
PageStatus ps = PageStatus.Normal;
DateTime creationDateTime = new DateTime(2000, 1, 1);
if(fields.Length == 2) ps = PageStatus.Normal;
if(fields.Length >= 3) {
switch(fields[2].ToLower()) {
case "locked":
ps = PageStatus.Locked;
break;
case "public":
ps = PageStatus.Public;
break;
case "normal":
ps = PageStatus.Normal;
break;
default:
try {
creationDateTime = DateTime.Parse(fields[2]);
}
catch {
// Use the Date/Time of the file
FileInfo fi = new FileInfo(Settings.PagesDirectory + fields[1]);
creationDateTime = fi.CreationTime;
}
break;
}
}
if(fields.Length == 4) {
creationDateTime = DateTime.Parse(fields[3]);
}
result[i] = new LocalPageInfo(fields[0], this, ps, creationDateTime, fields[1]);
}
return result;
}
}
private bool PageExists(PageInfo page) {
PageInfo[] pages = AllPages;
PageNameComparer comp = new PageNameComparer();
for(int i = 0; i < pages.Length; i++) {
if(comp.Compare(pages[i], page) == 0) return true;
}
return false;
}
/// <summary>
/// Gets all the Categories.
/// </summary>
/// <remarks>The array is unsorted.</remarks>
public CategoryInfo[] AllCategories {
get {
string tmp;
lock(locker) {
tmp = Tools.LoadFile(Settings.CategoriesFile).Replace("\r", "");
}
string[] lines = tmp.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
CategoryInfo[] result = new CategoryInfo[lines.Length];
string[] fields;
for(int i = 0; i < lines.Length; i++) {
fields = lines[i].Split('|');
CategoryInfo cat = new CategoryInfo(fields[0], this);
List<string> pages = new List<string>();
for(int k = 0; k < fields.Length - 1; k++) {
if(PageExists(new PageInfo(fields[k + 1], this, PageStatus.Normal, DateTime.Now))) {
pages.Add(fields[k + 1]);
}
}
cat.Pages = pages.ToArray();
result[i] = cat;
}
return result;
}
}
private bool CategoryExists(CategoryInfo category) {
CategoryInfo[] cats = AllCategories;
CategoryNameComparer comp = new CategoryNameComparer();
for(int i = 0; i < cats.Length; i++) {
if(comp.Compare(cats[i], category) == 0) return true;
}
return false;
}
/// <summary>
/// Adds a new Category.
/// </summary>
/// <param name="name">The Category name.</param>
/// <returns>The correct CategoryInfo object.</returns>
public CategoryInfo AddCategory(string name) {
lock(locker) {
Tools.AppendFile(Settings.CategoriesFile, "\r\n" + name);
CategoryInfo[] cats = AllCategories;
CategoryInfo res = new CategoryInfo(name, this);
res.Pages = new string[0];
return res;
}
}
/// <summary>
/// Renames a Category.
/// </summary>
/// <param name="category">The Category to rename.</param>
/// <param name="newName">The new Name.</param>
/// <returns>The correct CategoryInfo object.</returns>
public CategoryInfo RenameCategory(CategoryInfo category, string newName) {
lock(locker) {
CategoryInfo[] cats = AllCategories;
CategoryNameComparer comp = new CategoryNameComparer();
for(int i = 0; i < cats.Length; i++) {
if(comp.Compare(cats[i], category) == 0) {
CategoryInfo tmp = new CategoryInfo(newName, this);
tmp.Pages = cats[i].Pages;
cats[i] = tmp;
DumpCategories(cats);
return tmp;
}
}
}
return null;
}
/// <summary>
/// Removes a Category.
/// </summary>
/// <param name="category">The Category to remove.</param>
/// <returns>True if the Category has been removed successfully.</returns>
public bool RemoveCategory(CategoryInfo category) {
lock(locker) {
CategoryInfo[] cats = AllCategories;
CategoryNameComparer comp = new CategoryNameComparer();
for(int i = 0; i < cats.Length; i++) {
if(comp.Compare(cats[i], category) == 0) {
List<CategoryInfo> tmp = new List<CategoryInfo>(cats);
tmp.Remove(tmp[i]);
DumpCategories(tmp.ToArray());
return true;
}
}
}
return false;
}
/// <summary>
/// Merges two Categories.
/// </summary>
/// <param name="source">The source Category.</param>
/// <param name="destination">The destination Category.</param>
/// <returns>True if the Categories have been merged successfully.</returns>
/// <remarks>The <b>destination</b> Category remains, while the <b>source</b> Category is deleted, and all its Pages re-binded in the <b>destination</b> Category.</remarks>
public CategoryInfo MergeCategories(CategoryInfo source, CategoryInfo destination) {
lock(locker) {
CategoryInfo[] cats = AllCategories;
int idx1 = -1, idx2 = -1;
CategoryNameComparer comp = new CategoryNameComparer();
for(int i = 0; i < cats.Length; i++) {
if(comp.Compare(cats[i], source) == 0) idx1 = i;
if(comp.Compare(cats[i], destination) == 0) idx2 = i;
if(idx1 != -1 && idx2 != -1) break;
}
if(idx1 == -1 || idx2 == -1) return null;
List<CategoryInfo> tmp = new List<CategoryInfo>(cats);
List<string> newPages = new List<string>(cats[idx2].Pages);
for(int i = 0; i < cats[idx1].Pages.Length; i++) {
bool found = false;
for(int k = 0; k < newPages.Count; k++) {
if(newPages[k].ToLower().Equals(cats[idx1].Pages[i].ToLower())) {
found = true;
break;
}
}
if(!found) {
newPages.Add(cats[idx1].Pages[i]);
}
}
tmp[idx2].Pages = newPages.ToArray();
tmp.Remove(tmp[idx1]);
DumpCategories(tmp.ToArray());
CategoryInfo newCat = new CategoryInfo(destination.Name, this);
newCat.Pages = newPages.ToArray();
return newCat;
}
}
/// <summary>
/// Gets the Content of a Page.
/// </summary>
/// <param name="page">The Page to get the content of.</param>
/// <returns>The Page Content.</returns>
public PageContent GetContent(PageInfo page) {
if(page == null) return null;
return ExtractContent(Tools.LoadFile(Settings.PagesDirectory + ((LocalPageInfo)page).File), page);
}
private PageContent ExtractContent(string data, PageInfo pageInfo) {
if(data == null) return null;
// Structure
// Page Title
// Username|DateTime[|Comment] --- The comment is optional
// ##PAGE##
// Content...
data = data.Replace("\r", "");
string[] lines = data.Split('\n');
string[] fields = lines[1].Split('|');
int idx = data.IndexOf("##PAGE##") + 8 + 1;
return new PageContent(pageInfo, lines[0], fields[0], DateTime.Parse(fields[1]), fields.Length == 3 ? Tools.UnescapeString(fields[2]) : "", data.Substring(idx));
}
/// <summary>
/// Backups a Page.
/// </summary>
/// <param name="page">The Page to backup.</param>
/// <returns>True if the Page has been backupped successfully.</returns>
public bool Backup(PageInfo page) {
List<int> backups = GetBackups(page);
LocalPageInfo pg = (LocalPageInfo)page;
int rev = (backups.Count > 0 ? backups[backups.Count - 1] + 1 : 0);
File.Copy(Settings.PagesDirectory + pg.File,
Settings.PagesDirectory + Path.GetFileNameWithoutExtension(pg.File) + "." + Tools.GetVersionString(rev) + Path.GetExtension(pg.File));
return true;
}
/// <summary>
/// Gets the Backup/Revision numbers of a Page.
/// </summary>
/// <param name="page">The Page to get the Backup of.</param>
/// <returns>The list of Backup/Revision numbers.</returns>
public List<int> GetBackups(PageInfo page) {
string[] files = Directory.GetFiles(Settings.PagesDirectory, Path.GetFileNameWithoutExtension(((LocalPageInfo)page).File) + ".*.cs");
List<int> result = new List<int>();
for(int i = 0; i < files.Length; i++) {
string num = Path.GetFileNameWithoutExtension(files[i]).Substring(page.Name.Length + 1);
try {
// If num is not actually a number, this would crash
result.Add(int.Parse(num));
}
catch { }
}
return result;
}
/// <summary>
/// Gets the Content of a Backup.
/// </summary>
/// <param name="page">The Page.</param>
/// <param name="revision">The revision.</param>
/// <returns>The content.</returns>
public PageContent GetBackupContent(PageInfo page, int revision) {
if(!PageExists(page)) return null;
LocalPageInfo pg = (LocalPageInfo)page;
string filename = Path.GetFileNameWithoutExtension(pg.File) + "." + Tools.GetVersionString(revision) + Path.GetExtension(pg.File);
return ExtractContent(Tools.LoadFile(Settings.PagesDirectory + filename), page);
}
/// <summary>
/// Forces to overwrite or create a Backup.
/// </summary>
/// <param name="content">The Backup content.</param>
/// <param name="revision">The revision.</param>
/// <returns>True if the Backup has been created successfully.</returns>
public bool SetBackupContent(PageContent content, int revision) {
StringBuilder sb = new StringBuilder();
sb.Append(content.Title);
sb.Append("\r\n");
sb.Append(content.User);
sb.Append("|");
sb.Append(content.LastModified.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
sb.Append("\r\n##PAGE##\r\n");
sb.Append(content.Content);
string filename = "";
if(content.PageInfo is LocalPageInfo) {
// Use local file
LocalPageInfo pg = (LocalPageInfo)content.PageInfo;
filename = Path.GetFileNameWithoutExtension(pg.File) + "." + Tools.GetVersionString(revision) + Path.GetExtension(pg.File);
}
else {
filename = content.PageInfo.Name + "." + Tools.GetVersionString(revision) + ".cs";
}
Tools.WriteFile(Settings.PagesDirectory + filename, sb.ToString());
return true;
}
/// <summary>
/// Adds a new Page.
/// </summary>
/// <param name="name">The Name of the Page.</param>
/// <param name="creationDateTime">The creation Date/Time.</param>
/// <returns>The correct PageInfo object.</returns>
public PageInfo AddPage(string name, DateTime creationDateTime) {
if(PageExists(new PageInfo(name, this, PageStatus.Normal, DateTime.Now))) return null;
lock(locker) {
Tools.AppendFile(Settings.PagesFile, "\r\n" + name + "|" + name + ".cs" + "|NORMAL|" + creationDateTime.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
File.Create(Settings.PagesDirectory + name + ".cs").Close();
}
return new LocalPageInfo(name, this, PageStatus.Normal, creationDateTime, name + ".cs");
}
/// <summary>
/// Renames a Page.
/// </summary>
/// <param name="page">The Page to rename.</param>
/// <param name="newName">The new Name.</param>
/// <returns>True if the Page has been renamed successfully.</returns>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -