CloudNotes之桌面客戶端篇:增強的筆記列表


今天,我發布了CloudNotes的一個更新版本:1.0.5484.36793。這個版本與1.0.5472.20097不同的是,它擁有增強的筆記列表,與之前單調的列表系統相比,新的筆記列表不僅可以顯示筆記的摘要內容,而且還可以從筆記中抽取第一張圖片,並顯示圖片的詳細信息:

image

怎么樣?相比之前的筆記列表,現在的設計是不是能夠展示更豐富的信息呢?

升級到最新版本

如果在讀完我的第一篇關於CloudNotes的文章,《CloudNotes:一個雲端個人筆記系統》之后,已經安裝並體驗了上一個版本的CloudNotes,那么,當你重新打開CloudNotes桌面客戶端時,你將在登錄界面,或者主界面的狀態欄部分看到發現新版本更新的通知信息:

image

image

你可以點擊這個信息來進入新版本更新系統。然而不幸的是,更新系統會告訴你,更新失敗,原因是因為你打開了Windows 7的用戶帳戶控制(UAC)的功能,更新程序不具備訪問C:\Program Files (x86)目錄的權限。解決方案有如下兩種:

  1. 進入控制面板,關閉用戶帳戶控制(UAC)功能
  2. 點擊這里】下載CloudNotes更新程序的補丁包,下載以后,將zip文件解壓並覆蓋CloudNotes安裝目錄下的Updater目錄中(比如:C:\Program Files (x86)\daxnet\CloudNotes Desktop Client)的所有文件,然后重新通過CloudNotes桌面客戶端進入升級程序,即可完成升級

如果你是第一次看到有CloudNotes這么個玩意兒,並且打算嘗試使用的話,請直接【點擊這里】下載版本1.0.5484.36793,它是截止到本文撰寫時的最新版本,包含了這個最新的日志列表和修復的CloudNotes更新程序。

技術實現

在此大致介紹一下我是如何實現這種全新的筆記列表界面的,並簡要介紹一下如何讓應用程序在UAC下具有訪問文件系統資源的權限。

增強的筆記列表

說起來也有趣,有一天我看到有個同事在用Evernote,覺得它的筆記列表視圖做得挺不錯,還有縮略圖:

image

給人的感覺就是能夠在簡單的視圖中體現更多的筆記信息,讓人更容易地找到需要查看的筆記內容。於是我也在想,我的CloudNotes桌面客戶端是否也可以實現類似的效果。

經過一番研究之后,我決定對目前筆記列表所使用的樹形控件進行自定義:從System.Windows.Forms.TreeView類繼承一個自定義的TreeViewEx類型,並使用OwnerDrawText的自定義繪畫方式,對每個樹狀節點(TreeNode)進行重繪,以達到類似的效果。

在TreeNode進行重繪時(就是在OnDrawNode事件處理過程中),TreeViewEx會根據當前節點上的TreeNodeExItem數據,對樹狀節點進行重繪,從而達到上面截圖中展示的效果。實現起來其實並不困難,就是需要有耐心,文字的顏色、定位、圖片的尺寸等等,都需要花時間慢慢調整。這部分代碼我也不多做解釋了,朋友們請自行參考CloudNotes.DesktopClient項目下Controls\TreeViewEx.cs源代碼文件中的實現即可。相比之下,更為有趣技術點主要有:

從HTML中獲得純文本信息

這就是用於顯示筆記的摘要文字部分。由於筆記是HTML格式存儲的,而摘要部分卻僅需要筆記文字的開頭一段即可,因此,就需要從HTML中去掉HTML的標記,從中提取可讀的純文本信息。在CloudNotes中,我是使用下面的擴展方法來實現這個功能的。該方法同時被WebAPI和桌面客戶端使用。通過代碼可以看到,我僅僅將筆記中的前100個文字作為筆記的摘要信息。

/// <summary>
/// Extract the description from the html.
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static string ExtractDescription(this string html)
{
    var plainText = html.RemoveHtmlTags();
    return plainText.Substring(0, plainText.Length < 100 ? plainText.Length : 100);
}

/// <summary>
/// Removes all the HTML tags and bad characters from the given HTML string.
/// </summary>
/// <param name="html">The source HTML string.</param>
/// <returns></returns>
private static string RemoveHtmlTags(this string html)
{
    html = HttpUtility.UrlDecode(html);
    html = HttpUtility.HtmlDecode(html);

    html = RemoveTag(html, "<!--", "-->");
    html = RemoveTag(html, "<script", "</script>");
    html = RemoveTag(html, "<style", "</style>");

    //replace matches of these regexes with space
    html = Tags.Replace(html, " ");
    html = NotOkCharacter.Replace(html, " ");
    html = SingleSpacedTrim(html);

    return html;
}

提取筆記中的第一張圖片

為了顯示筆記圖片的縮略圖,首先需要提取筆記中的第一張圖片,然后再通過圖像處理函數產生縮略圖。話不多說,直接上代碼:

/// <summary>
/// The regular expression for extracting the Src value from an HTML Img tag.
/// </summary>
public const string ImgSrcFormatPattern = @"<img[^>]*?src\s*=\s*[""']?([^'"" >]+?)[ '""][^>]*?>";

/// <summary>
/// Extract the thumbnail image from the html.
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static string ExtractThumbnailImageBase64(this string html)
{
    var imageBase64List = html.GetImgSrcBase64FromHtml();
    string result = null;
    if (imageBase64List != null && imageBase64List.Any())
    {
        result = imageBase64List.First();
    }
    return result;
}

/// <summary>
/// 
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private static IEnumerable<string> GetImgSrcBase64FromHtml(this string html)
{
    var matchesImgSrc = Regex.Matches(html, Constants.ImgSrcFormatPattern,
        RegexOptions.IgnoreCase | RegexOptions.Singleline);
    if (matchesImgSrc.Count == 0)
        return null;
    List<string> result = new List<string>();
    foreach (Match m in matchesImgSrc)
    {
        var href = m.Groups[1].Value;
        var pos = href.IndexOf("base64,", StringComparison.InvariantCultureIgnoreCase);
        pos += 7;
        result.Add(href.Substring(pos, href.Length - pos).Trim());
    }
    return result;
} 

縮略圖的產生

縮略圖的產生代碼是在TreeViewEx控件中實現的,基本思路其實很簡單,就是根據圖片的長寬進行等比縮小即可。代碼如下:

private static Image FixedSize(Image imgPhoto, int width, int height, Color clearColor)
{
    int sourceWidth = imgPhoto.Width;
    int sourceHeight = imgPhoto.Height;
    int sourceX = 0;
    int sourceY = 0;
    int destX = 0;
    int destY = 0;

    float nPercent;
    float nPercentW;
    float nPercentH;

    nPercentW = ((float)width / (float)sourceWidth);
    nPercentH = ((float)height / (float)sourceHeight);
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = Convert.ToInt16((width - (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = Convert.ToInt16((height - (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Bitmap bmPhoto = new Bitmap(width, height,
        PixelFormat.Format24bppRgb);
    bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
        imgPhoto.VerticalResolution);

    Graphics grPhoto = Graphics.FromImage(bmPhoto);
    grPhoto.Clear(clearColor);
    grPhoto.InterpolationMode =
        InterpolationMode.HighQualityBicubic;

    grPhoto.DrawImage(imgPhoto,
        new Rectangle(destX, destY, destWidth, destHeight),
        new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
        GraphicsUnit.Pixel);

    grPhoto.Dispose();
    return bmPhoto;
}

讓應用程序在UAC下具有訪問文件系統資源的權限

這是之前版本中CloudNotes桌面客戶端更新程序遇到的一個問題。如果用戶將CloudNotes安裝在系統目錄中,更新程序在試圖更新CloudNotes桌面客戶端的版本的時候,就會遇到錯誤,提示無法更新。根本原因是用戶在Windows系統中啟用了用戶帳戶控制(UAC),即使當前登錄系統的帳戶是管理員,也並不代表該用戶對系統中的所有資源都具備管理員權限。在這種情況下,即使是由管理員啟動的更新程序,也無法將下載並解壓好的文件復制到系統目錄下。

要解決這一問題,就需要在.NET應用程序的Manifest里指定requestedExecutionLevel,將其指定為requireAdministrator,於是,在執行更新程序的時候,會彈出以下標准對話框,讓用戶對應用程序所作出的行為進行確認:

image

此時只需點擊“是”按鈕即可完成更新。

更改Manifest其實很簡單,只需要在應用程序項目上,通過Visual Studio的“添加項目”對話框,即可添加App.manifest文件,將文件中的requestedExecutionLevel改為requireAdministrator即可:

image

有關CloudNotes WebAPI以及桌面客戶端的其它內容,請大家直接上https://github.com/daxnet/CloudNotes站點直接查看源代碼即可。不懂的地方可以在此留言。

接下來??

我是打算一步步對CloudNotes進行功能和性能完善的,接下來要做的事情還有太多。在每次完成新功能更新時,我都會出博客文章進行介紹。如果沒有新功能,我也會穿插介紹已有功能的相關技術實現。就目前而言,打算接下來的版本逐步提供以下功能改進:

  • 本地緩存和服務器同步系統 - 目前每次打開和保存筆記,都是與服務器直接相連的,不僅增大服務器負載,而且用戶體驗也不夠流暢
  • 插件系統 - 任何感興趣的朋友都可以通過插件系統,為CloudNotes桌面客戶端編寫插件,比如,直接將網頁抓取成日志等
  • 用戶之間的互信和筆記共享服務
  • 文檔結構視圖 - 通過分析HTML文檔,提供層級的文檔結構視圖,方便用CloudNotes進行寫作的用戶

等等等等。。。。。。讓我們一起期待吧。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM