如何向 Unity Launcher 添加针对最近使用文件的动态、应用程序特定的快速列表?

如何向 Unity Launcher 添加针对最近使用文件的动态、应用程序特定的快速列表?

使用启动器中的动态快捷列表访问 LibreOffice 中最近使用的文档将是一个很棒的功能。关于如何创建自定义静止的快速列表

但有谁能就如何构建一个动态的lo 中最近使用的文档的快速列表?

Ubuntu wiki 有一个非常简短的描述关于如何使用 python 或 vala 创建快速列表。我对这两种方法都没有经验,也没有找到动态快速列表的全面示例脚本。因此,我正在寻找一些更简单的方法来实现它,或者寻找已经做过/见过它的人。

答案1

在应用程序启动器中添加动态“最近使用”部分

满的与上述应用程序集成动态快速列表-最有可能需要完成的条目从内部应用程序。毕竟,有关使用的文件的最直接信息来自应用程序本身。

然而,由于编辑源代码超出了我们的工作范围,所以这不是我们要走的路。

然后呢?

这并不意味着我们不能从“外部”获得几乎完全相同的结果,甚至可能以更灵活和通用的方式。我们需要的所有信息都可以在动态更新的文件中找到:~/.local/share/recently-used.xbel,从中我们可以检索打开文件的完整历史记录、相应的日期和时间信息以及所使用的应用程序。

此外,添加动态地将更新部分添加到启动器中可以作为“传统”(静态)部分的一部分完成。解决方案的关键是创建一个流程来处理上述操作,而不会给系统增加明显的负担。
正如在链接从问题来看,一些无论如何都需要后台进程来跟踪变化并传递指令。

下面的脚本基本上就是这么做的。

解决方案;后台脚本

以下脚本中的值专门针对LibreOffice及其文档设置的。无需任何编辑,即可使用它来添加最近使用-部分添加到LibreOffice-Writer启动器。它将显示由任何LibreOffice模块打开的最后 10 个使用的文档。

不过,解决方案是添加“最近使用”部分到许多.desktop包含中的文件的应用程序/usr/share/applications。由于文件~/.local/share/recently-used.xbelGtk相关的,因此很可能包含Gtk窗口的应用程序将成为我们的潜在候选者(即,如果应用程序打开并编辑文件)。此外,要显示的文件数量是任意的。

外观

该解决方案在 Unity 启动器中的目标启动器中添加一个部分,显示任意数量的最近使用的文件,例如:

  • 显示最后七个文件:

    在此处输入图片描述

  • 或最后十个文件:

    在此处输入图片描述

  • 然而,同样容易的是,我们可以给gedit启动器一个动态部分,显示最后打开的七个文件gedit(见下图)

如何使用

假设您已预先安装了 LibreOffice(下载的版本没有脚本所需的引用.desktop文件,但在其他地方,如果您需要设置单独下载的 LO 版本,请提及)/usr/share/applications

  1. 将下面的脚本复制到一个空文件中,保存为dynamic_recent.pyLibreOffice进程名称为soffice,已在脚本中正确设置。

    #!/usr/bin/env python3
    import subprocess
    import os
    import time
    import shutil
    
    # --- set the number of docs to show in recently used
    n = 7
    # --- set the process name of the targeted application
    application = "soffice"
    #--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
    #    else the value should be the same as in application = (above)
    open_cmd = "soffice"
    # --- set the targeted .desktop file (e.g. "gedit.desktop")
    target = "libreoffice-writer.desktop"
    
    # --- don't change anything below
    home = os.environ["HOME"]+"/.local/share"
    loc = home+"/applications/"+target
    recdata = home+"/recently-used.xbel"
    
    def runs(app):
        try:
            # see if the application is running
            app = subprocess.check_output(["pgrep", app]).decode("utf-8")
        except subprocess.CalledProcessError:
            return False
        else:
            return True
    
    def get_lines():
        # retrieve information from the records:
        # -> get bookmark line *if* the application is in the exec= line
        with open(recdata) as infile:
            db = []
            for l in infile:
                if '<bookmark href="file://' in l:
                    sub = l
                elif 'exec="&apos;'+application in l:
                    db.append(sub)
        # fix bug in xbel -file in 15.04
        relevant = [l.split('="') for l in set(db) if all([not "/tmp" in l, "." in l])]
        relevant = [[it[1][7:-7], it[-2][:-10]] for it in relevant]
        relevant.sort(key=lambda x: x[1])
        return [item[0].replace("%20", " ") for item in relevant[::-1][:n]]
    
    def create_section(line):
        # create shortcut section
        name = line.split("/")[-1]
        return [[
            "[Desktop Action "+name+"]",
            "Name="+name,
            "Exec="+open_cmd+" '"+line+"'",
            "\n",
            ], name]
    
    def setup_dirs():
        # copy the global .desktop file to /usr/share/applications/
        glo = "/usr/share/applications/"+target
        if not os.path.exists(loc):
            shutil.copy(glo,loc)
    
    def edit_launcher(newdyn, target, actionlist):
        # read the current .desktop file
        ql = [list(item) for item in list(enumerate(open(loc).read().splitlines()))]
        # find the Actions= line
        currlinks = [l for l in ql if "Actions=" in l[1]]
        # split the line (if it exists)  by the divider as delimiter 
        linkline = currlinks[0][1].split("divider1")[0] if currlinks else None
        # define the shortcut sections, belonging to the dynamic section (below the divider)
        lowersection = [l for l in ql if "[Desktop Action divider1]" in l]
        # compose the new Actions= line
        addlinks = (";").join(actionlist) + ";"
        if linkline:
            newlinks = linkline + addlinks
            ql[currlinks[0][0]][1] = newlinks
            # get rid of the "dynamic" section  
            ql = ql[:lowersection[0][0]] if lowersection else ql
            # define the new file
            ql = [it[1] for it in ql]+newdyn
            with open(loc, "wt") as out:
                for l in ql:
                    out.write(l+"\n")
        else:
            newlinks = "Acrions="+addlinks
    
    setup_dirs()
    lines1 = []
    
    while True:
        time.sleep(2)
        # if the application does not run, no need for a check of .xbel
        if runs(application):
            lines2 = get_lines()
            # (only) if the list of recently used changed: edit the quicklist
            if lines1 != lines2:
                actionlist = ["divider1"]
                newdyn = [
                    "[Desktop Action divider1]",
                    "Name=" + 37*".",
                    "\n",
                    ]
                for line in lines2:
                    data = create_section(line)
                    actionlist.append(data[1])
                    section = data[0]
                    for l in section:
                        newdyn.append(l)
                edit_launcher(newdyn, target, actionlist)           
            lines1 = lines2
    
  2. 在脚本的头部,你可以设置一些选项:

    # --- set the number of docs to show in recently used
    n = 7
    # --- set the process name of the targeted application
    application = "soffice"
    #--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
    #    else the value should be the same as in application = (above)
    open_cmd = "soffice"
    # --- set the targeted .desktop file (e.g. "gedit.desktop")
    target = "libreoffice-writer.desktop"
    

    大多数选项都是不言而喻的,如果您想将动态部分添加到LO-Writer启动器,请保留所有内容。如果不想,请设置适当的启动器。

  3. 通过从终端运行来测试运行脚本:

    python3 /path/to/dynamic_recent.py
    
  4. 脚本将全局.desktop文件复制到~/.local/share/applications(在本例中~/.local/share/applications/libreoffice-writer.desktop)。将本地副本拖到启动器(否则您需要注销/登录)。

  5. 如果一切正常,请将其添加到启动应用程序:Dash > 启动应用程序 > 添加。添加命令:

    python3 /path/to/dynamic_recent.py
    

在其他应用程序上使用它

如上所述,您可以轻松使用脚本将动态“最近使用”部分添加到其他应用程序的启动器。为此,请参阅gedit脚本头部部分的示例设置:

# --- set the number of docs to show in recently used
n = 7
# --- set the process name of the targeted application
application = "gedit"
#--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
#    else the value should be the same as in application = (above)
open_cmd = "gedit"
# --- set the targeted .desktop file (e.g. "gedit.desktop")
target = "gedit.desktop"

在此处输入图片描述

怎么运行的

  • 该脚本定期查看文件以查找匹配的文件,并使用(processname: )~/.local/share/recently-used.xbel打开LibreOfficesoffice

    它使用一种非常快的算法来实现这一点,一次性“扫描”整个文件,以检索所需的行(每个“记录”两行)。结果是脚本的效率非常低。

  • 一旦从文件中检索到相关行,就按日期/时间对这些行进行排序,从而创建相应应用程序最近使用的“前十名”(或任何其他数字)文件。

  • 仅有的如果此列表发生变化,则.desktop文件会更新。

在后台运行该脚本时,我没有注意到也没有测量到系统的任何额外负载。

已在 14.04 / 15.10 上测试

如何恢复原始启动器

只需删除启动器的本地副本即可~/.local/share/applications

笔记

  • 如果你使用Unity 快速列表编辑器要编辑启动器(快速列表),您应避免使用动态更新的“上次使用”部分(来自此答案)来编辑启动器。使用快速列表编辑器所做的编辑将立即被脚本覆盖。

  • 您可以手动编辑快捷列表,但请确保添加新项目(在左边)divider1Actions=-行

    Actions=Window;Document;分隔符1;aap.sh;Todo;pscript_2.py;currdate;bulkmail_llJacob;verhaal;test doc;

    所有项目在右侧属于divider1动态更新的部分。


主要編輯

刚刚进行了一些重大改进:

  1. 现在的脚本仅有的在目标应用程序运行时检查.xbel文件(因为如果应用程序不运行,最近使用列表就不会发生变化)。该脚本已经很不实用了,但现在,只关注应用程序是否运行,这对您的系统来说就更没意义了。
  2. 在 15.04+ 版本中,.xbel文件重复提及了新文件,一个带有扩展名,一个不带有扩展名。现在已消除此影响。

相关内容