CloudNotes之桌面客户端篇:增强的笔记列表

今天,我发布了CloudNotes的一个更新版本:1.0.5484.36793。这个版本与1.0.5472.20097不同的是,它拥有增强的笔记列表,与之前单调的列表系统相比,新的笔记列表不仅可以显示笔记的摘要内容,而且还可以从笔记中抽取第一张图片,并显示图片的详细信息:

怎么样?相比之前的笔记列表,现在的设计是不是能够展示更丰富的信息呢?

升级到最新版本

如果在读完我的第一篇关于CloudNotes的文章,《CloudNotes:一个云端个人笔记系统》之后,已经安装并体验了上一个版本的CloudNotes,那么,当你重新打开CloudNotes桌面客户端时,你将在登录界面,或者主界面的状态栏部分看到发现新版本更新的通知信息:

你可以点击这个信息来进入新版本更新系统。然而不幸的是,更新系统会告诉你,更新失败,原因是因为你打开了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,觉得它的笔记列表视图做得挺不错,还有缩略图:

给人的感觉就是能够在简单的视图中体现更多的笔记信息,让人更容易地找到需要查看的笔记内容。于是我也在想,我的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,于是,在执行更新程序的时候,会弹出以下标准对话框,让用户对应用程序所作出的行为进行确认:

此时只需点击“是”按钮即可完成更新。

更改Manifest其实很简单,只需要在应用程序项目上,通过Visual Studio的“添加项目”对话框,即可添加App.manifest文件,将文件中的requestedExecutionLevel改为requireAdministrator即可:

有关CloudNotes WebAPI以及桌面客户端的其它内容,请大家直接上https://github.com/daxnet/CloudNotes站点直接查看源代码即可。不懂的地方可以在此留言。

接下来??

我是打算一步步对CloudNotes进行功能和性能完善的,接下来要做的事情还有太多。在每次完成新功能更新时,我都会出博客文章进行介绍。如果没有新功能,我也会穿插介绍已有功能的相关技术实现。就目前而言,打算接下来的版本逐步提供以下功能改进:

  • 本地缓存和服务器同步系统 - 目前每次打开和保存笔记,都是与服务器直接相连的,不仅增大服务器负载,而且用户体验也不够流畅
  • 插件系统 - 任何感兴趣的朋友都可以通过插件系统,为CloudNotes桌面客户端编写插件,比如,直接将网页抓取成日志等
  • 用户之间的互信和笔记共享服务
  • 文档结构视图 - 通过分析HTML文档,提供层级的文档结构视图,方便用CloudNotes进行写作的用户

等等等等。。。。。。让我们一起期待吧。。

时间: 2024-10-05 10:10:44

CloudNotes之桌面客户端篇:增强的笔记列表的相关文章

CloudNotes之桌面客户端篇:笔记撰写样式的支持

最近在CloudNotes桌面客户端中新增了笔记撰写样式的功能.当用户新建笔记的时候,可以在输入笔记标题的同时,选择笔记撰写样式,由安装包默认提供的样式主要有默认样式(Default).羊皮纸样式(Leather Paper)以及Word 2013样式(Microsoft Word 2013).选择笔记样式的时候,还提供了预览功能,用户可以直接预览样式效果: 当然,为了方便操作,用户可以在设置界面选择默认使用的样式,从而每次新建笔记时,默认使用的样式就会自动被选中,减少用户的操作次数.设置界面中

CloudNotes之桌面客户端篇:插件系统的实现

[CloudNotes版本更新历史与各版本下载地址请点击此处] [CloudNotes中文系列文章汇总列表请点击此处] [查看CloudNotes源代码请点击此处] 有时候,同一个名词,针对不同的人群,应该采用不同的表达方式.比如插件的概念,对于程序员而言,可以将其称为插件,或者扩展.对于用户而言,或许"扩展功能"一词会更加贴切.本文还是脱离不了码农的气质,继续讨论技术问题,因此,我会以"插件"一词进行描述. 概述 从1.0.5504.38654版本开始,Cloud

Mina airQQ聊天 客户端篇(三)

开发工具 (FlashBuilder4.7) 程序类型(Adobe Air) Flex Air做的桌面程序,效果还挺好看的,最主要是Socket这一块,它也是异步的,并且在Flex中的事件机制比较强大(个人认为) 有改一些样式,重新看看新的效果吧: 大致的实现方式: 在WindowedApplication中包含登陆窗口和主界面,用Flex中的状态来切换,聊天窗口时Window组件,好友列表用树菜单 实现好友分组,好友上线时改成在线图标,收到消息时头像抖动,聊天显示实现图文混排,系统托盘,其它貌

互联网江湖,桌面客户端框架技术比武大会

By 技术怪咖 欧阳森林 导读:在互联网时代,如何将一个好的idea快速的转化为产品,如何在原有产品中增加新的特性,是产品能够快速的推向市场.快速占领的关键.因此,作为客户端的架构选型,面临哪几方面的需求?资深前端工程师欧阳森林针对其专业领域的经验,有着自己独到的见解. 前言 自从互联网江湖上出现了一部叫做"云"的秘籍,大大小小的门派,纷纷对外宣称自己掌握了"云"的核心,各种"云"应用层出不穷,Service的各种架构在一次次的华山论剑上大放异彩

&quot;xaml+cs&quot;桌面客户端跨平台初体验

"Xaml+C#"桌面客户端跨平台初体验 前言 ??随着 .Net 5的到来,微软在 .Net 跨平台路上又开始了一个更高的起点.回顾.Net Core近几年的成果,可谓是让.Net重生了一次. ??Asp .Net Core跨平台解决了Windows服务器昂贵的费用和不能长时间待机的问题,让Asp程序能够跑在Linux甚至Mac上.从博客园里.Net分类可以看到,每天都可以涌现大批Asp .Net Core的技术文章,越来越多的开发者或者公司开始尝试这个船新的跨平台框架. ??然鹅,

《nodejs+gulp+webpack基础实战篇》课程笔记(四)-- 实战演练

一.用gulp 构建前端页面(1)---静态构建 npm install gulp-template --save-dev 通过这个插件,我们可以像写后台模板(譬如PHP)一样写前端页面.我们首先学习一下写法. 现在我们创建一个新任务:创建一个裸的index.html文件,然后在body里面写上 ,我的年龄是:<%= age %> 下载好gulp-template,我们引用并配置 var gulp_tpl = require("gulp-template"); gp.tas

在连接windows2008时,报错:由于这台计算机没有远程桌面客户端访问许可证,远程会话被中断

前两天连接服务器的时候弹出:由于这台计算机没有远程桌面客户端访问许可证,远程会话被中断的对话框提示.前一段还在用都是好好的,怎么一下子就不行了呢?然后找了一下解决方案,解决方案很简单. 解决方案: 打开本机注册表,注册表子项:HKEY_LOCAL_MACHINESOFTWAREMicrosoftMSLicensing,对,你没有看错,就是这个,不管他下面有没有东西,将整个子项删除.将MSLicensing删除. 但,原因是什么呢???

使用node-webkit开发Clover桌面客户端的一些记录(一)

首先说一说Clover. 这是一个OA产品,是我们公司组建我们技术部以来最最重要的一项工作 -- 开发企业内部使用的管理系统."Clover"这个名字是我们老大起的,拆开看是"C"+"lover"."lover"都懂是啥,而这个"C"呢,其实就是"Code",因为我们老大是一个(狂热的)编码爱好者(汗...),精通很多门语言,所以就隐晦的把自己的爱好写进项目名称,就连我们测试服务器的地址

网盘桌面客户端的技术难点

最近在做网盘桌面客户端,遇到如下技术难点: 1.网盘如何本地虚拟化(类似金山网盘等桌面快捷方式等功能) 2.如何使用Shell扩展技术 3.是否需要使用COM组件编程技术 4.如何做文件实时同步功能 以上难点到目前还有好多未知的情况,如果有人知道或者做过类似的桌面shell扩展,麻烦告知 (*^__^*) 嘻嘻…… http://blog.csdn.net/esonpo/article/details/11128719