Есть ли меню «Места» для Ubuntu Unity?

11

Я хотел бы знать, возможно ли разместить вкладку «Места» в верхнем меню Ubuntu, например, CentOS, Debian и т. Д.

Спасибо

Ulises CT
источник
Легко, но что именно это должно показать?
Джейкоб Влейм
основные папки (домашняя страница, файлы для загрузки, документы и т. д.), а также папки с закладками, такие как debian и centos
Ulises CT
Я вижу, напишу один сегодня или завтра, если никто не сделал раньше, чем я :), или, может быть, один уже существует (вы имеете в виду индикатор, верно?)
Джейкоб Vlijm
поищите "Места меню Debian" в Google Images, и вы поймете, что я имею в виду.
Ulises CT
Нет, это было классическое меню. Все, что я нашел, было устаревшим материалом с дюймом пыли на нем. Я могу довольно быстро написать основной (и будет). Я хотел бы объединить его с этим: askubuntu.com/questions/803869/… , что сделало бы его интересным проектом. Поэтому первый выстрел сегодня или завтра не будет последним. Хороший вопрос
Джейкоб Влейм

Ответы:

12

Я перепробовал несколько существующих, но не смог найти индикатор рабочих мест . Те, что я нашел, были устаревшими, PPA больше не поддерживали.

Модульное меню Мест

Итак, ниже недавно написанного: индикатор Places & Files для Ubuntu .

введите описание изображения здесь 2

Версия PPA является модульной ; Вы можете выбрать, что показать в меню:

[ введите описание изображения здесь]

В полной версии:

введите описание изображения здесь

... или самый маленький, показывает только недавно использованный:

введите описание изображения здесь

Установка из ppa

sudo add-apt-repository ppa:vlijm/placesfiles
sudo apt-get update
sudo apt-get install placesfiles

Упрощенная версия для отображения меню мест, закладок и недавно использованных файлов

Описание и (начальный) код

Сценарий

#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread
import os
import subprocess

class Indicator():
    def __init__(self):

        currpath = os.path.dirname(os.path.realpath(__file__))
        self.home = os.environ["HOME"]
        self.bmark_file = os.path.join(self.home, ".config/gtk-3.0/bookmarks")
        self.def_file = os.path.join(self.home, ".config/user-dirs.dirs")
        self.recdata = os.path.join(self.home, ".local/share/recently-used.xbel")
        self.n = 10
        self.app = 'places'
        iconpath = os.path.join(currpath, "dir_icon.png")
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
        self.indicator.set_label("Places", self.app)
        self.indicator.set_menu(self.create_menu())
        # the thread:
        self.update = Thread(target=self.check_recent)
        self.update.setDaemon(True)
        self.update.start()

    def create_menu(self):
        # creates the (initial) menu
        self.menu = Gtk.Menu()
        # separator
        initial = Gtk.MenuItem("Fetching list...")
        menu_sep = Gtk.SeparatorMenuItem()
        self.menu.append(initial)
        self.menu.append(menu_sep)
        # item_quit.show() 
        self.menu.show_all()
        return self.menu

    def open_directory(self, *args):
        index = self.menu.get_children().index(self.menu.get_active())
        selection = self.menu_items2[index-2]
        self.execute(["xdg-open", selection])

    def open_file(self, *args):
        index = self.submenu.get_children().index(self.submenu.get_active())
        selection = self.submenu2[index] 
        self.execute(["xdg-open", selection])

    def go_special(self, button, target):
        self.execute(["xdg-open", target])

    def connect(self, button):
        self.execute("nautilus-connect-server")

    def set_new(self):
        # update the list, appearing in the menu
        for i in self.menu.get_children():
            self.menu.remove(i)
        home_mention = Gtk.MenuItem("⌂ Home")
        home_mention.connect("activate", self.go_special, self.home)
        self.menu.append(home_mention)
        # separator
        menu_sep1 = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep1)
        for app in self.menu_items2:
            sub = Gtk.MenuItem("⏍ "+app.split("/")[-1])
            self.menu.append(sub)
            sub.connect('activate', self.open_directory)
        # separator
        menu_sep2 = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep2)
        # network
        network = "network:///"
        network_mention = Gtk.MenuItem("⇄ Network")
        network_mention.connect("activate", self.go_special, network)
        self.menu.append(network_mention)
        connect_mention = Gtk.MenuItem("⮁ Connect to server")
        connect_mention.connect("activate", self.connect)
        self.menu.append(connect_mention)
        # separator
        menu_sep3 = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep3)
        # computer
        computer = "computer:///"
        computer_mention = Gtk.MenuItem("⛁ Computer")
        computer_mention.connect("activate", self.go_special, computer)
        self.menu.append(computer_mention)
        recent_mention = Gtk.MenuItem("⁕ Recent files")
        self.menu.append(recent_mention)

        self.submenu = Gtk.Menu()
        for f in self.submenu2:
            recent = Gtk.MenuItem(f)
            recent.connect("activate", self.open_file)
            self.submenu.append(recent)
        recent_mention.set_submenu(self.submenu)
        # separator
        menu_sep6 = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep6)
        # quit
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        self.menu.append(item_quit)
        self.menu.show_all()

    def run_about(self, *args):
        self.execute("/opt/upfront/code/runabout")

    def check_recent(self):
        self.menu_items1 = []; self.submenu1 = []
        while True:
            time.sleep(4)
            self.menu_items2 = self.get_bookmarks()
            self.submenu2 = self.get_files()

            if any([self.menu_items2 != self.menu_items1,
                self.submenu2 != self.submenu1]):
                GObject.idle_add(
                    self.set_new, 
                    priority=GObject.PRIORITY_DEFAULT
                    )
            self.menu_items1 = self.menu_items2
            self.submenu1 = self.submenu2

    def stop(self, source):
        Gtk.main_quit()

    def get_bookmarks(self):
        loc_bookmarks = [
            l.replace("file://", "") for l in open(self.bmark_file).read().splitlines()\
            if l.startswith("file://")
            ]
        netw_bookmarks = [
            l for l in open(self.bmark_file).read().splitlines()\
            if l.startswith("smb://")
            ]
        defaults = [
            os.path.join(self.home, l.replace('"', "").split("$HOME/")[-1]) for l in \
            open(self.def_file).read().splitlines() if all\
            (["$HOME/" in l, l.startswith("XDG")])
            ]
        return [self.replace_sc(m.split(" ")[0]).rstrip("/") for m in list(
            set(loc_bookmarks+defaults+netw_bookmarks))]

    def replace_sc(self, path):
        for c in [("%23", "#"), ("%5D", "]"), ("%5E", "^"),
                  ("file://", ""), ("%20", " ")]:
            path = path.replace(c[0], c[1])
        return path

    def execute(self, command):
        subprocess.Popen(command)

    def get_files(self):
        # create the list of recently used files
        used = [l for l in open(self.recdata) if all([
                    '<bookmark href="file://' in l, not "/tmp" in l, "." in l])]
        relevant = [l.split('="') for l in set(used)]
        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][:self.n]]


Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()

Как использовать (если не установлен из ppa)

  1. Скопируйте скрипт в пустой файл, сохраните его как places_indicator.py
  2. Сохраните значок (щелкните правой кнопкой мыши> сохранить как) с точным именем:

    dir_icon.png
    

    введите описание изображения здесь

    ..в одном и том же каталоге, что и скрипт.

  3. Тест - запустите скрипт командой:

    python3 /path/to/places_indicator.py
    
  4. Если все работает нормально, добавьте его в Startup Applications: Dash> Startup Applications> Add. Добавьте команду:

    /bin/bash -c "sleep 10 && python3 /path/to/places_indicator.py
    

Об индикаторе

Индикатор показывает:

  1. Домашний каталог
  2. Все каталоги (локальные закладки и smb) в
    • ~/.config/gtk-3.0/bookmarks
    • ~/.config/user-dirs.dirs
  3. сеть
  4. Подключиться к сети
  5. компьютер
  6. Недавно использованные файлы (их можно легко изменить на 10 латов)

Изменение / добавление / удаление закладок обновляются динамически

Якоб Влейм
источник
довольно хорошо, я попробовал это на Unity и работает спасибо! Но я решил использовать Gnome, потому что он выглядит более красиво, но я буду использовать его и для недавней функции filess! спасибо
Ulises CT
@UlisesCT Ах, спасибо, что попробовали Unity, несмотря на то, что вы переключились!
Джейкоб Влейм
Да! проблема в том, что я пришел из Windows для настольных ПК и никогда не использовал графические средства в Linux, только терминал на CentOS для серверов и тому подобное, и когда я установил Ubuntu из Ubuntu.es, я подумал, что его графический интерфейс был именно этим и не знал есть Gnome и Unity, которые вы можете выбрать (я пропустил вкладку Places, потому что она была на CentOS, которую я пытался попробовать в качестве рабочего стола, но это отстой). Хорошо продолжать учиться
Ulises CT
Вау, это обязательство - написание новой программы для удовлетворения этой потребности! Очень впечатлен, молодец @JacobVlijm! Почему это версия 0.5.1-1, если вы только что написали это?
Ads20000
@ Ads20000 Спасибо! Несколько улучшений; (пере) перемещенные или переименованные файлы теперь помечены, если вы (попытаетесь) открыть их, отображается уведомление, другой значок недавних сообщений теперь также работает с 14.04, незначительная оптимизация кода (фильтрация специальных символов в именах файлов) и т. д.
Джейкоб Влейм
8

Обновление февраль / 24/2017 : теперь в индикаторе есть возможность закрепления веб-ссылок.

Вступление

ПРИМЕЧАНИЕ. Предыдущая версия этого ответа может быть найдена в истории изменений, хотя она больше не актуальна.

Показатель, представленный ниже, предназначен для другого вопроса, но, поскольку появилась возможность, я решил выпустить его здесь. Индикатор файлов - это простой индикатор для доступа к файлам и папкам пользователя. Это позволяет проверять недавно использованные файлы, создавать закладки для файлов и каталогов. В частности, меню «Места» имеет особое отношение к этому вопросу.

введите описание изображения здесь

введите описание изображения здесь

Как видно из скриншота, индикатор также поддерживает локали, отличные от английского, поэтому, если ваша система использует что-то отличное от английского, он будет работать.

Обновление : индикатор теперь также поддерживает запуск файлов .desktop, которые были закреплены. Например, если у вас есть закрепленный firefox.desktop, он запустит firefox. Таким образом, индикатор можно использовать в качестве быстрого запуска программ. Эта функция находится на пути к PPA на момент написания (19 ноября, 19:53 по Гринвичу, обработка должна занять около 24 часов), но она уже есть на github и здесь, в обновленном исходном коде.

введите описание изображения здесь

Получение индикатора

Индикатор доступен из моего личного PPA, а также с GitHub . Используйте следующие шаги, чтобы получить его:

sudo add-apt-repository ppa:1047481448-2/sergkolo
sudo apt-get update
sudo apt-get install files-indicator

Исходный код

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#
# Author: Serg Kolo , contact: 1047481448@qq.com
# Date: November 19 , 2016
# Purpose: appindicator for accessing files and folders
# Tested on: Ubuntu 16.04 LTS
#
#
# Licensed under The MIT License (MIT).
# See included LICENSE file or the notice below.
#
# Copyright © 2016 Sergiy Kolodyazhnyy
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import gi
gi.require_version('AppIndicator3', '0.1')
gi.require_version('Notify', '0.7')
from gi.repository import GLib as glib
from gi.repository import AppIndicator3 as appindicator
from gi.repository import Gtk as gtk
from gi.repository import Gio
from gi.repository import Notify
from collections import OrderedDict
# from collections import OrderedDict
import urllib.parse
import subprocess
import copy
import shutil
import dbus
import math
import json
import os

class FilesIndicator(object):

    def __init__(self):
        self.app = appindicator.Indicator.new(
            'files-indicator', "document-open-recent",
            appindicator.IndicatorCategory.HARDWARE
        )
        self.user_home = os.path.expanduser('~')
        filename = '.pinned_files.json'
        self.pinned_list = os.path.join(self.user_home,filename)

        self.config = os.path.join(self.user_home,'.files_indicator.json')
        self.max_items = 15
        self.name_length = 20
        self.read_config()

        self.app.set_status(appindicator.IndicatorStatus.ACTIVE)

        self.cached_files = self.get_recent_files()
        self.make_menu()
        self.update()

    def read_config(self,*args):
        config = {}
        try:
            with open(self.config) as f:
                 config = json.load(f)

        except FileNotFoundError:
            print('>>> ',self.config,' not found.Creating one')
            f = open(self.config,'w')
            config = {'max_items':self.max_items,
                      'name_length':self.name_length
            }
            json.dump(config,f,indent=4)
            f.close()
        except json.JSONDecodeError:
            print(">>> Can't read ",self.pinned_list,',may be corrupt')
            return None
        else:
            self.max_items = config['max_items']
            self.name_length = config['name_length']

    def add_menu_item(self, menu_obj, item_type, image, label, action, args):
        """ dynamic function that can add menu items depending on
            the item type and other arguments"""
        menu_item, icon = None, None
        if item_type is gtk.ImageMenuItem and label:
            menu_item = gtk.ImageMenuItem.new_with_label(label)
            menu_item.set_always_show_image(True)
            if '/' in image:
                icon = gtk.Image.new_from_file(image)
            else:
                icon = gtk.Image.new_from_icon_name(image, 48)
            menu_item.set_image(icon)
        elif item_type is gtk.ImageMenuItem and not label:
            menu_item = gtk.ImageMenuItem()
            menu_item.set_always_show_image(True)
            if '/' in image:
                icon = gtk.Image.new_from_file(image)
            else:
                icon = gtk.Image.new_from_icon_name(image, 16)
            menu_item.set_image(icon)
        elif item_type is gtk.MenuItem:
            menu_item = gtk.MenuItem(label)
        elif item_type is gtk.SeparatorMenuItem:
            menu_item = gtk.SeparatorMenuItem()
        if action:
            menu_item.connect('activate', action, *args)

        menu_obj.append(menu_item)
        menu_item.show()

    def get_user_dirs(self,*args):
        user_dirs = []
        for index,val in glib.UserDirectory.__enum_values__.items():
            if index == 8: continue
            dir = glib.get_user_special_dir(index)
            if dir: user_dirs.append(dir)
        return user_dirs

    def get_file_icon(self,*args):
        if args[-1].endswith('.desktop'):
            desk_file = Gio.DesktopAppInfo.new_from_filename(args[-1])
            icon = desk_file.get_icon()
            if type(icon) == Gio.ThemedIcon:
                themed_name = icon.get_names()[0]
                theme = gtk.IconTheme.get_default()
                name = theme.lookup_icon(themed_name, 48, 0).get_filename()
            if type(icon) == Gio.FileIcon:
                name = icon.get_file().get_uri()

            icon_url= urllib.parse.unquote(name).replace('file://','') 
            return icon_url

        file = Gio.File.new_for_path(args[-1])
        file_info = file.query_info("standard::*",0)
        icon_string = file_info.get_icon().to_string()
        if 'folder-' in icon_string:
            return icon_string.split()[-2]
        return icon_string.split()[-1]

    def get_recent_files(self,*args):
        manager = gtk.RecentManager.get_default()
        try:
            files = OrderedDict()
            for index,item in enumerate(manager.get_items(),1):
                    uri = item.get_uri()
                    uri_decoded = urllib.parse.unquote(uri)
                    filepath = uri_decoded.replace('file://','')
                    if not os.path.exists(filepath): continue
                    basename = os.path.basename(uri_decoded)
                    files[basename] = filepath
                    if index == self.max_items:
                        break
        except Exception as e:
            print(e)
            return None
        finally:  return files

    def callback(self,*args):
        self.update()

    def update(self,*args):
        current_files = self.get_recent_files()
        if current_files != self.cached_files:
             self.make_menu()
             self.cached_files = current_files
        glib.timeout_add_seconds(3,self.callback)

    def add_submenu(self,top_menu,label):
        menuitem = gtk.MenuItem(label)
        submenu = gtk.Menu()
        menuitem.set_submenu(submenu)
        top_menu.append(menuitem)
        menuitem.show()
        return submenu

    def make_menu(self):
        if hasattr(self, 'app_menu'):
            for item in self.app_menu.get_children():
                    self.app_menu.remove(item)
        else:
            self.app_menu = gtk.Menu()
        recent = self.add_submenu(self.app_menu,'Recent Files')
        recent_dict = self.get_recent_files()

        content = [recent,gtk.ImageMenuItem,'gtk-add',
                   'Add to Recent Files',self.add_recent,[None]
        ]      
        self.add_menu_item(*content) 

        content = [recent,gtk.ImageMenuItem,'user-trash',
                   'Clear recent files list',self.clear_recent,[None]
        ]      
        self.add_menu_item(*content)

        content = [recent,gtk.SeparatorMenuItem,
                   None,None,
                   None,[None]
        ]
        self.add_menu_item(*content)
        self.add_menu_item(*content) 
        if not recent_dict:
            content = [recent,gtk.MenuItem,None,
                       'No items',None,None
            ]
            self.add_menu_item(*content)
            last = None
            for i in recent.get_children():
                last = i
            last.set_sensitive(False)
        else:
            for name,data in recent_dict.items():
                icon = self.get_file_icon(data)
                content = [recent, gtk.ImageMenuItem,
                           icon, name[:self.name_length],
                           self.open_item, [data]
                ]
                self.add_menu_item(*content)

        # Pinned files
        bookmarks = self.add_submenu(self.app_menu,'Pinned Files')
        content = [bookmarks,gtk.ImageMenuItem,
                   'bookmark_add','Pin a file',
                   self.pin_file,[bookmarks,None]
        ]
        self.add_menu_item(*content)

        content = [bookmarks,gtk.ImageMenuItem,
                   'remove','Remove item',
                   self.remove_pinned,['files']
        ]
        self.add_menu_item(*content)

        content = [bookmarks,gtk.ImageMenuItem,
                   'user-trash','Remove All',
                   self.remove_all_pinned,[None]
        ]
        self.add_menu_item(*content)
        content = [bookmarks,gtk.SeparatorMenuItem,
                   None,None,
                   None,[None]
        ]
        self.add_menu_item(*content)
        self.add_menu_item(*content) 

        pinned_files = self.get_pinned()

        if (pinned_files and 
            'files' in pinned_files.keys() and
            pinned_files['files']):
            for filepath in pinned_files['files']:
                icon = self.get_file_icon(filepath) 
                content = [bookmarks,gtk.ImageMenuItem,
                           icon,os.path.basename(filepath),
                           self.open_item,[filepath]
                ]
                self.add_menu_item(*content)
        else:
            content = [bookmarks,gtk.MenuItem,None,
                       'No items',None,None
            ]
            self.add_menu_item(*content)
            last = None
            for i in bookmarks.get_children():
                last = i
            last.set_sensitive(False)

        places = self.add_submenu(self.app_menu,'Places')
        content = [places,gtk.ImageMenuItem,'add',
                   'Pin Directory',self.pin_dir,[None]
        ]

        self.add_menu_item(*content)

        content = [places,gtk.ImageMenuItem,
                   'remove','Remove Pinned',
                   self.remove_pinned,['dirs']
        ]
        self.add_menu_item(*content)

        content = [places,gtk.SeparatorMenuItem,
                   None,None,
                   None,[None]
        ]
        self.add_menu_item(*content)

        content = [places,gtk.MenuItem,None,
                   'Standard Dirs',None,None
        ]
        self.add_menu_item(*content)
        last = None
        for i in places.get_children():
            last = i
        last.set_sensitive(False)
        for dir in self.get_user_dirs():
            icon = self.get_file_icon(dir)
            content = [places,gtk.ImageMenuItem,icon,
                       os.path.basename(dir),self.open_item,[dir]

            ]
            self.add_menu_item(*content)

        content = [places,gtk.SeparatorMenuItem,
                   None,None,
                   None,[None]
        ]
        self.add_menu_item(*content)

        content = [places,gtk.MenuItem,None,
                   'Pinned Dirs',None,None
        ]
        self.add_menu_item(*content)
        last = None
        for i in places.get_children():
            last = i
        last.set_sensitive(False)

        if (pinned_files and 
           'dirs' in pinned_files.keys() and
           pinned_files['dirs']):
            for dir in pinned_files['dirs']:
                icon = self.get_file_icon(dir)
                print(icon)
                content = [places,gtk.ImageMenuItem,icon,
                           os.path.basename(dir),self.open_item,[dir]

                ]
                self.add_menu_item(*content)
        else:
            content = [places,gtk.MenuItem,None,
                       'No items',None,None
            ]
            self.add_menu_item(*content)
            last = None
            for i in places.get_children():
                last = i
            last.set_sensitive(False)

        content = [self.app_menu,gtk.SeparatorMenuItem,
                   None,None,
                   None,[None]
        ]
        self.add_menu_item(*content)
        content = [self.app_menu,gtk.ImageMenuItem,'exit',
                   'quit',self.quit,[None]
        ]
        self.add_menu_item(*content)
        self.app.set_menu(self.app_menu)

    def check_directory(self,*args):
        current_set = set(os.listdir(args[-1]))
        return current_set - self.cached_set


    def get_pinned(self,*args):
        try:
            with open(self.pinned_list) as f:
                 return json.load(f,object_pairs_hook=OrderedDict)

        except FileNotFoundError:
            print('>>> ',self.pinned_list,' not found')
            return None
        except json.JSONDecodeError:
            print(">>> Can't read ",self.pinned_list,',may be corrupt')
            return None

    def pin_dir(self,*args):
        # TODO
        current_list = self.get_pinned()
        if not current_list:
                current_list = OrderedDict()
                current_list['dirs'] = []
                f = open(self.pinned_list,'w')
                f.write("")
                f.close()

        if not args[-1]:
                cmd = "zenity --file-selection --directory --separator || --multiple"
                dirs = self.run_cmd(cmd.split())
        else:
                dirs = args[-1]

        dir_list = []
        if not dirs: return None
        dir_list = dirs.decode().strip().split("||")
        if not 'dirs' in current_list.keys():
             current_list['dirs'] = []
        for f in dir_list:
                #icon = self.get_file_icon(f)
                current_list['dirs'].append(f)

        with open(self.pinned_list,'w') as f:
                json.dump(current_list,f,indent=4)
        self.make_menu()

    def pin_file(self,*args):
        current_list = self.get_pinned()
        if not current_list:
                current_list = OrderedDict()
                current_list['files'] = []
                f = open(self.pinned_list,'w')
                f.write("")
                f.close()
        if not args[-1]:
                cmd = "zenity --file-selection --separator || --multiple "
                files = self.run_cmd(cmd.split())
        else:
                files = args[-1]

        file_list = []
        if not files: return None
        file_list = files.decode().strip().split("||")
        if not 'files' in current_list.keys():
            current_list['files'] = []
        for f in file_list:
                #icon = self.get_file_icon(f)
                current_list['files'].append(f)

        with open(self.pinned_list,'w') as f:
                json.dump(current_list,f,indent=4)
        self.make_menu()

    def remove_all_pinned(self,*args):
        try:
            #os.unlink(self.pinned_list)

            with open(self.pinned_list) as f:
                pinned = json.load(f)
            pinned.pop('files')       
            with open(self.pinned_list,'w') as f:
                    json.dump(pinned,f,indent=4)
        except:
            pass
        finally:
            self.make_menu()

    def remove_pinned(self,*args):
        key = args[-1]
        pinned = self.get_pinned() 
        if not pinned: return
        cmd_str = "zenity --forms --add-combo Remove --combo-values"
        vals = "|".join(pinned[key])
        cmd = cmd_str.split() + [vals]
        item = self.run_cmd(cmd)
        if item: 
            path = item.decode().strip()
            index = pinned[key].index(path)
            pinned[key].pop(index)
            with open(self.pinned_list,'w') as f:
                json.dump(pinned,f,indent=4)
            self.make_menu()

    def add_recent(self,*args):
        cmd = "zenity --file-selection --separator || --multiple "
        files = self.run_cmd(cmd.split())
        file_list = []
        if not files: return
        file_list = files.decode().strip().split("||")
        items = ['file://' + f for f in file_list]
        for f in items: gtk.RecentManager().get_default().add_item(f)

    def clear_recent(self,*args):
        try:
            gtk.RecentManager.get_default().purge_items()
            self.make_menu()
        except:
            pass

    def open_item(self,*args):
        #self.run_cmd(['xdg-open',args[-1]]) 
        if args[-1].endswith('.desktop'):
            desk_file = Gio.DesktopAppInfo.new_from_filename(args[-1])
            return desk_file.launch_uris()
        return subprocess.Popen(['xdg-open',args[-1]])

    def quit(self,*args):
        gtk.main_quit()

    def run_cmd(self, cmdlist):
        """ utility: reusable function for running external commands """
        #new_env = dict(os.environ)
        #new_env['LC_ALL'] = 'C'
        try:
            stdout = subprocess.check_output(cmdlist) #env=new_env)
        except subprocess.CalledProcessError:
            pass
        else:
            if stdout:
                return stdout

    def run(self):
        """ Launches the indicator """
        try:
            gtk.main()
        except KeyboardInterrupt:
            pass

    def quit(self, *args):
        """ closes indicator """
        gtk.main_quit()


def main():
    """ defines program entry point """
    indicator = FilesIndicator()
    indicator.run()

if __name__ == '__main__':
  try:
    main()
  except  KeyboardInterrupt:
    gtk.main_quit()

Конфигурации

Индикатор настраивается с помощью двух файлов JSON, хранящихся в домашнем каталоге пользователя.

~/.files_indicator.json управляет пользовательским интерфейсом, длиной пунктов меню и максимальными числами в меню последних файлов.

{
    "name_length": 30,
    "max_items": 10
}

~/.pinned_files.jsonКонтролирует списки возлагали файлов и папок. Каждый элемент представляет собой список / массив.

{
    "dirs": [
        "/home/xieerqi/\u56fe\u7247/Wallpapers"
    ],
    "files": [
        "/home/xieerqi/work_in_progress/videonauth_code.py",
        "/home/xieerqi/work_in_progress/spin_button.py"
    ]
}
Сергей Колодяжный
источник
Вау, впечатлило, что вы создали решение этой проблемы тоже! : D
Ads20000
@ Ads20000 Спасибо :) Этот индикатор изначально предназначался только для последних файлов. Когда я увидел вопрос, я подумал, что эту функцию было бы неплохо добавить и к индикатору, плюс ее было очень просто реализовать - мне потребовалось одно утро и 2 чашки кофе :)
Сергей Колодяжный,
Ваша работа также превратилась в OMG! Ubuntu! статья ! : D
Ads20000
Да, я видел это :)
Сергей Колодяжный
0

Ладно, ребята, я просто установил Ubuntu-Gnome, включил расширение 'Places' в инструменте Tweak и получил его. Должен сказать, что Ubuntu Gnome выглядит намного лучше, чем Unity

Смотрите вкладку "Лугарес"

Ulises CT
источник
Мудрый выбор. С самого начала было очевидно, что вы склоняетесь к использованию GNOME, поскольку он более знаком вам по CentOS. Кстати, то, что они используют в CentOS - это GNOME Flashback. Он визуально похож на предыдущую версию, но использует новые технологии. Что касается Unity, это может быть не для всех, хотя мне лично очень не нравится GNOME за их постоянное удаление функций и усложнение разработки.
Сергей Колодяжный
Да, точно, я "нуб" в Linux или "устарел", как вы предпочитаете это говорить. Я имею в виду, что я всегда использовал терминал для серверов на CentOS, и не очень много графических вещей, я не знал, что были разные графические опции, такие как Unity и Gnome, я просто думал, что Ubuntu может выглядеть только так, как это делает из загрузочный пакет ubuntu.com, CentOS, как это делается на официальной веб-странице, и т. д. Не знал, что вы можете выбрать различные графические варианты. Хорошо продолжать учиться. @Serg
Ulises CT
Позвольте мне задать вам вопрос: если вам абсолютно необходимо было использовать рабочий стол Unity, какие еще вещи вы хотели бы иметь? (Очевидно, я пытаюсь исследовать идеи для будущего использования :)
Сергей Колодяжный,
Единственное, о чем я могу думать, это вкладка «Места» или «Приложения» (которые я на самом деле не использую), остальное доступно и в Unity. Думаю, что мне не нравится в gnome, так это то, что для меню приложений вы приходится нажимать кнопку в большинстве программ (типичное меню файла, редактирования и т. д.)
Ulises CT