redesign connection panel and use Avahi instead of profiles

This commit is contained in:
coderkun 2014-12-04 21:14:23 +01:00
commit 3935f6ae5f
4 changed files with 143 additions and 237 deletions

View file

@ -1,6 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<schemalist> <schemalist>
<schema path="/de/coderkun/mcg/" id="de.coderkun.mcg" gettext-domain="mcg"> <schema path="/de/coderkun/mcg/" id="de.coderkun.mcg" gettext-domain="mcg">
<key type="s" name="host">
<default>'localhost'</default>
<summary>MPD host</summary>
<description>MPD host to connect to</description>
</key>
<key type="i" name="port">
<default>6600</default>
<summary>MPD port</summary>
<description>MPD port to connect to</description>
</key>
<key type="s" name="image-dir">
<default>''</default>
<summary>Image dir</summary>
<description>Directory which a webserver is providing images on</description>
</key>
<key type="b" name="connected">
<default>false</default>
<summary>Connection state</summary>
<description>State of last connection</description>
</key>
<key type="ai" name="window-size"> <key type="ai" name="window-size">
<default>[800, 600]</default> <default>[800, 600]</default>
<summary>Window size</summary> <summary>Window size</summary>
@ -11,11 +31,6 @@
<summary>Window maximized</summary> <summary>Window maximized</summary>
<description>Window maximized state.</description> <description>Window maximized state.</description>
</key> </key>
<key type="i" name="profile">
<default>0</default>
<summary>Last selected profile</summary>
<description>The index of the last selected profile used to connect to the MPD server.</description>
</key>
<key type="i" name="panel"> <key type="i" name="panel">
<range min="1" max="3"/> <range min="1" max="3"/>
<default>1</default> <default>1</default>

Binary file not shown.

View file

@ -18,6 +18,7 @@ import threading
import urllib import urllib
from gi.repository import Gio, Gtk, Gdk, GObject, GdkPixbuf, GLib from gi.repository import Gio, Gtk, Gdk, GObject, GdkPixbuf, GLib
from gi.repository import Avahi
import mcg import mcg
@ -27,9 +28,12 @@ import mcg
class Application(Gtk.Application): class Application(Gtk.Application):
TITLE = "MPDCoverGrid (Gtk)" TITLE = "MPDCoverGrid (Gtk)"
SETTINGS_BASE_KEY = 'de.coderkun.mcg' SETTINGS_BASE_KEY = 'de.coderkun.mcg'
SETTING_HOST = 'host'
SETTING_PORT = 'port'
SETTING_CONNECTED = 'connected'
SETTING_IMAGE_DIR = 'image-dir'
SETTING_WINDOW_SIZE = 'window-size' SETTING_WINDOW_SIZE = 'window-size'
SETTING_WINDOW_MAXIMIZED = 'window-maximized' SETTING_WINDOW_MAXIMIZED = 'window-maximized'
SETTING_PROFILE = 'profile'
SETTING_PANEL = 'panel' SETTING_PANEL = 'panel'
SETTING_ITEM_SIZE = 'item-size' SETTING_ITEM_SIZE = 'item-size'
SETTING_SORT_ORDER = 'sort-order' SETTING_SORT_ORDER = 'sort-order'
@ -156,6 +160,9 @@ class Window(Gtk.ApplicationWindow):
""") """)
self.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), styleProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) self.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), styleProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
self.get_style_context().add_class(Window.STYLE_CLASS_BG_TEXTURE) self.get_style_context().add_class(Window.STYLE_CLASS_BG_TEXTURE)
self._panels[Window._PANEL_INDEX_CONNECTION].set_host(self._settings.get_string(Application.SETTING_HOST))
self._panels[Window._PANEL_INDEX_CONNECTION].set_port(self._settings.get_int(Application.SETTING_PORT))
self._panels[Window._PANEL_INDEX_CONNECTION].set_image_dir(self._settings.get_string(Application.SETTING_IMAGE_DIR))
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE)) self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE)) self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Application.SETTING_SORT_ORDER)) self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Application.SETTING_SORT_ORDER))
@ -169,7 +176,7 @@ class Window(Gtk.ApplicationWindow):
self._header_bar.connect_signal(HeaderBar.SIGNAL_CONNECT, self.on_header_bar_connect) self._header_bar.connect_signal(HeaderBar.SIGNAL_CONNECT, self.on_header_bar_connect)
self._header_bar.connect_signal(HeaderBar.SIGNAL_PLAYPAUSE, self.on_header_bar_playpause) self._header_bar.connect_signal(HeaderBar.SIGNAL_PLAYPAUSE, self.on_header_bar_playpause)
self._header_bar.connect_signal(HeaderBar.SIGNAL_SET_VOLUME, self.on_header_bar_set_volume) self._header_bar.connect_signal(HeaderBar.SIGNAL_SET_VOLUME, self.on_header_bar_set_volume)
self._panels[Window._PANEL_INDEX_CONNECTION].connect_signal(ConnectionPanel.SIGNAL_PROFILE_CHANGED, self.on_connection_panel_profile_changed) self._panels[Window._PANEL_INDEX_CONNECTION].connect_signal(ConnectionPanel.SIGNAL_CONNECTION_CHANGED, self.on_connection_panel_connection_changed)
self._panels[Window._PANEL_INDEX_PLAYLIST].connect_signal(PlaylistPanel.SIGNAL_CLEAR_PLAYLIST, self.on_playlist_panel_clear_playlist) self._panels[Window._PANEL_INDEX_PLAYLIST].connect_signal(PlaylistPanel.SIGNAL_CLEAR_PLAYLIST, self.on_playlist_panel_clear_playlist)
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_TOGGLE_FULLSCREEN, self.on_cover_panel_toggle_fullscreen) self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_TOGGLE_FULLSCREEN, self.on_cover_panel_toggle_fullscreen)
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_SET_SONG, self.on_cover_panel_set_song) self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_SET_SONG, self.on_cover_panel_set_song)
@ -195,7 +202,8 @@ class Window(Gtk.ApplicationWindow):
self.show_all() self.show_all()
self._infobar.hide() self._infobar.hide()
self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION]) self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION])
self._panels[Window._PANEL_INDEX_CONNECTION].select_profile(self._settings.get_int(Application.SETTING_PROFILE)) if self._settings.get_boolean(Application.SETTING_CONNECTED):
self._connect()
def on_resize(self, widget, event): def on_resize(self, widget, event):
@ -234,10 +242,10 @@ class Window(Gtk.ApplicationWindow):
# Panel callbacks # Panel callbacks
def on_connection_panel_profile_changed(self, index, profile): def on_connection_panel_connection_changed(self, host, port, password, image_dir):
self._settings.set_int(Application.SETTING_PROFILE, index) self._settings.set_string(Application.SETTING_HOST, host)
if ConnectionPanel.TAG_AUTOCONNECT in profile.get_tags(): self._settings.set_int(Application.SETTING_PORT, port)
self._connect() self._settings.set_string(Application.SETTING_IMAGE_DIR, image_dir)
def on_playlist_panel_clear_playlist(self): def on_playlist_panel_clear_playlist(self):
@ -353,12 +361,14 @@ class Window(Gtk.ApplicationWindow):
self._header_bar.set_sensitive(False, True) self._header_bar.set_sensitive(False, True)
if self._mcg.is_connected(): if self._mcg.is_connected():
self._mcg.disconnect() self._mcg.disconnect()
self._settings.set_boolean(Application.SETTING_CONNECTED, False)
else: else:
host = connection_panel.get_host() host = connection_panel.get_host()
port = connection_panel.get_port() port = connection_panel.get_port()
password = connection_panel.get_password() password = connection_panel.get_password()
image_dir = connection_panel.get_image_dir() image_dir = connection_panel.get_image_dir()
self._mcg.connect(host, port, password, image_dir) self._mcg.connect(host, port, password, image_dir)
self._settings.set_boolean(Application.SETTING_CONNECTED, True)
def _connect_connected(self): def _connect_connected(self):
@ -564,90 +574,83 @@ class Panel(mcg.Base):
class ConnectionPanel(Panel, Gtk.HBox): class ConnectionPanel(Panel, Gtk.VBox):
SIGNAL_PROFILE_CHANGED = 'profile-changed' SIGNAL_CONNECTION_CHANGED = 'connection-changed'
TAG_AUTOCONNECT = 'autoconnect'
def __init__(self): def __init__(self):
Panel.__init__(self) Panel.__init__(self)
Gtk.HBox.__init__(self) Gtk.VBox.__init__(self)
self._profile_config = mcg.MCGProfileConfig() self._services = Gtk.ListStore(str, str, int)
self._profiles = Gtk.ListStore(str)
self._profile = None self._profile = None
# Widgets # Widgets
vbox = Gtk.VBox() hbox = Gtk.HBox()
self.pack_start(vbox, True, False, 0) self.pack_start(hbox, True, False, 0)
self._table = Gtk.Table(6, 2, False) grid = Gtk.Grid()
vbox.pack_start(self._table, True, False, 0) grid.set_column_spacing(5)
# Profile grid.set_column_homogeneous(True)
profile_box = Gtk.HBox() hbox.pack_start(grid, True, False, 0)
self._table.attach(profile_box, 0, 2, 0, 1) # Zeroconf
# Profile Selection zeroconf_box = Gtk.HBox()
self._profile_combo = Gtk.ComboBox.new_with_model(self._profiles) grid.add(zeroconf_box)
self._profile_combo.set_entry_text_column(0) # Zeroconf list
self._zeroconf_list = Gtk.TreeView(self._services)
self._zeroconf_list.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
self._profile_combo.pack_start(renderer, True) column = Gtk.TreeViewColumn("Zeroconf", renderer, text=0)
self._profile_combo.add_attribute(renderer, "text", 0) self._zeroconf_list.append_column(column)
profile_box.pack_start(self._profile_combo, True, True, 0) zeroconf_box.pack_start(self._zeroconf_list, True, True, 0)
# Profile Management # Separator
profile_button_box = Gtk.HBox() separator = Gtk.Separator.new(Gtk.Orientation.VERTICAL)
profile_box.pack_end(profile_button_box, False, True, 0) zeroconf_box.pack_end(separator, False, False, 5)
# New Profile # Connection grid
self._profile_new_button = Gtk.Button() connection_grid = Gtk.Grid()
self._profile_new_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.BUTTON)) grid.attach_next_to(connection_grid, zeroconf_box, Gtk.PositionType.RIGHT, 1, 1)
profile_button_box.add(self._profile_new_button)
# Delete Profile
self._profile_delete_button = Gtk.Button()
self._profile_delete_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON))
profile_button_box.add(self._profile_delete_button)
# Host # Host
host_label = Gtk.Label("Host:") host_label = Gtk.Label("Host:")
host_label.set_alignment(0, 0.5) host_label.set_alignment(0, 0.5)
self._table.attach(host_label, 0, 1, 1, 2) connection_grid.add(host_label)
self._host_entry = Gtk.Entry() self._host_entry = Gtk.Entry()
self._host_entry.set_text("localhost") self._host_entry.set_text("localhost")
self._table.attach(self._host_entry, 1, 2, 1, 2) connection_grid.attach_next_to(self._host_entry, host_label, Gtk.PositionType.BOTTOM, 1, 1)
# Port # Port
port_label = Gtk.Label("Port:") port_label = Gtk.Label("Port:")
port_label.set_alignment(0, 0.5) port_label.set_alignment(0, 0.5)
self._table.attach(port_label, 0, 1, 2, 3) connection_grid.attach_next_to(port_label, self._host_entry, Gtk.PositionType.BOTTOM, 1, 1)
adjustment = Gtk.Adjustment(6600, 1024, 9999, 1, 10, 10) adjustment = Gtk.Adjustment(6600, 1024, 9999, 1, 10, 10)
self._port_spinner = Gtk.SpinButton() self._port_spinner = Gtk.SpinButton()
self._port_spinner.set_adjustment(adjustment) self._port_spinner.set_adjustment(adjustment)
self._table.attach(self._port_spinner, 1, 2, 2, 3) connection_grid.attach_next_to(self._port_spinner, port_label, Gtk.PositionType.BOTTOM, 1, 1)
# Passwort # Passwort
password_label = Gtk.Label("Password:") password_label = Gtk.Label("Password:")
password_label.set_alignment(0, 0.5) password_label.set_alignment(0, 0.5)
self._table.attach(password_label, 0, 1, 3, 4) connection_grid.attach_next_to(password_label, self._port_spinner, Gtk.PositionType.BOTTOM, 1, 1)
self._password_entry = Gtk.Entry() self._password_entry = Gtk.Entry()
self._table.attach(self._password_entry, 1, 2, 3, 4) self._password_entry.set_input_purpose(Gtk.InputPurpose.PASSWORD)
self._password_entry.set_visibility(False)
connection_grid.attach_next_to(self._password_entry, password_label, Gtk.PositionType.BOTTOM, 1, 1)
# Image dir # Image dir
image_dir_label = Gtk.Label("Image Dir:") image_dir_label = Gtk.Label("Image Dir:")
image_dir_label.set_alignment(0, 0.5) image_dir_label.set_alignment(0, 0.5)
self._table.attach(image_dir_label, 0, 1, 4, 5) connection_grid.attach_next_to(image_dir_label, self._password_entry, Gtk.PositionType.BOTTOM, 1, 1)
self._image_dir_entry = Gtk.Entry() self._image_dir_entry = Gtk.Entry()
self._table.attach(self._image_dir_entry, 1, 2, 4, 5) connection_grid.attach_next_to(self._image_dir_entry, image_dir_label, Gtk.PositionType.BOTTOM, 1, 1)
# Autoconnect
self._autoconnect_button = Gtk.CheckButton("Autoconnect") # Zeroconf provider
self._table.attach(self._autoconnect_button, 1, 2, 5, 6) self._zeroconf_provider = ZeroconfProvider()
self._zeroconf_provider.connect_signal(ZeroconfProvider.SIGNAL_SERVICE_NEW, self.on_new_service)
# Signals # Signals
self._profiles.connect('row-changed', self.on_profiles_changed) self._zeroconf_list.get_selection().connect('changed', self.on_service_selected)
self._profiles.connect('row-inserted', self.on_profiles_changed) self._zeroconf_list.connect('focus-out-event', self.on_zeroconf_list_outfocused)
self._profiles.connect('row-deleted', self.on_profiles_changed)
self._profile_combo.connect("changed", self.on_profile_combo_changed)
self._profile_new_button.connect('clicked', self.on_profile_new_clicked)
self._profile_delete_button.connect('clicked', self.on_profile_delete_clicked)
self._host_entry.connect('focus-out-event', self.on_host_entry_outfocused) self._host_entry.connect('focus-out-event', self.on_host_entry_outfocused)
self._port_spinner.connect('value-changed', self.on_port_spinner_value_changed) self._port_spinner.connect('value-changed', self.on_port_spinner_value_changed)
self._password_entry.connect('focus-out-event', self.on_password_entry_outfocused) self._password_entry.connect('focus-out-event', self.on_password_entry_outfocused)
self._image_dir_entry.connect('focus-out-event', self.on_image_dir_entry_outfocused) self._image_dir_entry.connect('focus-out-event', self.on_image_dir_entry_outfocused)
self._autoconnect_button.connect('toggled', self.on_autoconnect_button_toggled)
# Actions # Actions
self._load_profiles() #self._load_profiles()
def get_name(self): def get_name(self):
@ -658,63 +661,37 @@ class ConnectionPanel(Panel, Gtk.HBox):
return "Server" return "Server"
def on_profiles_changed(self, *data): def on_new_service(self, service):
self._profile_config.save() name, host, port = service
self._services.append([name, host, port])
def on_profile_combo_changed(self, combo): def on_service_selected(self, selection):
(index, profile) = self._get_selected_profile() model, treeiter = selection.get_selected()
if profile is not None: if treeiter != None:
self._profile = profile service = model[treeiter]
self.set_host(self._profile.get('host')) self.set_host(service[1])
self.set_port(int(self._profile.get('port'))) self.set_port(service[2])
self.set_password(self._profile.get('password'))
self.set_image_dir(self._profile.get('image_dir'))
self._autoconnect_button.set_active(ConnectionPanel.TAG_AUTOCONNECT in self._profile.get_tags())
self._callback(ConnectionPanel.SIGNAL_PROFILE_CHANGED, index, profile)
def on_profile_new_clicked(self, widget): def on_zeroconf_list_outfocused(self, widget, event):
profile = mcg.MCGProfile() self._zeroconf_list.get_selection().unselect_all()
self._profile_config.add_profile(profile)
self._reload_profiles()
self._profile_combo.set_active(len(self._profiles)-1)
def on_profile_delete_clicked(self, widget):
(index, profile) = self._get_selected_profile()
if profile is not None:
self._profile_config.delete_profile(profile)
self._reload_profiles()
self._profile_combo.set_active(0)
def on_host_entry_outfocused(self, widget, event): def on_host_entry_outfocused(self, widget, event):
self._profile.set('host', widget.get_text()) self._call_back()
self._profiles.set(self._profile_combo.get_active_iter(), 0, widget.get_text())
def on_port_spinner_value_changed(self, widget): def on_port_spinner_value_changed(self, widget):
self._profile.set('port', self.get_port()) self._call_back()
def on_password_entry_outfocused(self, widget, event): def on_password_entry_outfocused(self, widget, event):
self._profile.set('password', widget.get_text()) self._call_back()
def on_image_dir_entry_outfocused(self, widget, event): def on_image_dir_entry_outfocused(self, widget, event):
self._profile.set('image_dir', widget.get_text()) self._call_back()
def on_autoconnect_button_toggled(self, widget):
tags = self._profile.get_tags()
if widget.get_active():
if ConnectionPanel.TAG_AUTOCONNECT not in tags:
tags.append(ConnectionPanel.TAG_AUTOCONNECT)
else:
if ConnectionPanel.TAG_AUTOCONNECT in tags:
tags.remove(ConnectionPanel.TAG_AUTOCONNECT)
self._profile.set_tags(tags)
def set_host(self, host): def set_host(self, host):
@ -754,31 +731,8 @@ class ConnectionPanel(Panel, Gtk.HBox):
return self._image_dir_entry.get_text() return self._image_dir_entry.get_text()
def select_profile(self, index): def _call_back(self):
if len(self._profiles) <= index: self._callback(ConnectionPanel.SIGNAL_CONNECTION_CHANGED, self.get_host(), self.get_port(), self.get_password(), self.get_image_dir())
index = 0
self._profile_combo.set_active(index)
def _load_profiles(self):
self._profile_config.load()
for profile in self._profile_config.get_profiles():
self._profiles.append([str(profile)])
def _reload_profiles(self):
self._profiles.clear()
for profile in self._profile_config.get_profiles():
self._profiles.append([str(profile)])
def _get_selected_profile(self):
index = self._profile_combo.get_active()
if index >= 0:
profiles = self._profile_config.get_profiles()
if index < len(profiles):
return (index, profiles[index])
return (-1, None)
@ -1493,3 +1447,45 @@ class StackSwitcher(mcg.Base, Gtk.StackSwitcher):
else: else:
self._temp_button = None self._temp_button = None
self._callback(StackSwitcher.SIGNAL_STACK_SWITCHED, self) self._callback(StackSwitcher.SIGNAL_STACK_SWITCHED, self)
class ZeroconfProvider(mcg.Base):
SIGNAL_SERVICE_NEW = 'service-new'
TYPE = '_mpd._tcp'
def __init__(self):
mcg.Base.__init__(self)
self._service_resolvers = []
self._services = {}
# Client
self._client = Avahi.Client(flags=0,)
self._client.start()
# Browser
self._service_browser = Avahi.ServiceBrowser(domain='local', flags=0, interface=-1, protocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, type=ZeroconfProvider.TYPE)
self._service_browser.connect('new_service', self.on_new_service)
self._service_browser.attach(self._client)
def on_new_service(self, browser, interface, protocol, name, type, domain, flags):
if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
service_resolver = Avahi.ServiceResolver(interface=interface, protocol=protocol, name=name, type=type, domain=domain, aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, flags=0,)
service_resolver.connect('found', self.on_found)
service_resolver.connect('failure', self.on_failure)
service_resolver.attach(self._client)
self._service_resolvers.append(service_resolver)
def on_found(self, resolver, interface, protocol, name, type, domain, host, date, port, *args):
if (host, port) not in self._services.keys():
service = (name,host,port)
self._services[(host,port)] = service
self._callback(ZeroconfProvider.SIGNAL_SERVICE_NEW, service)
def on_failure(self, resolver, date):
if resolver in self._service_resolvers:
self._service_resolvers.remove(resolver)

115
mcg.py
View file

@ -202,6 +202,11 @@ class Client(Base):
self._add_action(self._set_volume, volume) self._add_action(self._set_volume, volume)
def test(self):
self._logger.info("test")
self._add_action(self._test)
# Private methods # Private methods
def _connect(self, host, port, password): def _connect(self, host, port, password):
@ -836,116 +841,6 @@ class MCGConfig(configparser.ConfigParser):
class MCGProfileConfig(MCGConfig):
CONFIG_FILE = 'profiles.conf'
def __init__(self):
MCGConfig.__init__(self, MCGProfileConfig.CONFIG_FILE)
self._profiles = []
def add_profile(self, profile):
self._profiles.append(profile)
def delete_profile(self, profile):
if profile in self._profiles:
self._profiles.remove(profile)
self._force_default_profile()
def get_profiles(self):
return self._profiles
def load(self):
super().load()
count = 0
if self.has_section('profiles'):
if self.has_option('profiles', 'count'):
count = self.getint('profiles', 'count')
for index in range(count):
section = 'profile'+str(index+1)
if self.has_section(section):
profile = MCGProfile()
for attribute in profile.get_attributes():
if self.has_option(section, attribute):
profile.set(attribute, self.get(section, attribute))
self._profiles.append(profile)
self._force_default_profile()
def save(self):
if not self.has_section('profiles'):
self.add_section('profiles')
self.set('profiles', 'count', str(len(self._profiles)))
for index in range(len(self._profiles)):
profile = self._profiles[index]
section = 'profile'+str(index+1)
if not self.has_section(section):
self.add_section(section)
for attribute in profile.get_attributes():
self.set(section, attribute, str(profile.get(attribute)))
for section in self.sections()[len(self._profiles)+1:]:
self.remove_section(section)
super().save()
def _force_default_profile(self):
if len(self._profiles) == 0:
self._profiles.append(MCGProfile())
class MCGConfigurable:
def __init__(self):
self._attributes = []
def get(self, attribute):
return getattr(self, attribute)
def set(self, attribute, value):
setattr(self, attribute, value)
if attribute not in self._attributes:
self._attributes.append(attribute)
def get_attributes(self):
return self._attributes
class MCGProfile(MCGConfigurable):
def __init__(self):
MCGConfigurable.__init__(self)
self.set('host', "localhost")
self.set('port', 6600)
self.set('password', "")
self.set('image_dir', "")
self.set('tags', "")
def __str__(self):
return self.get("host")
def get_tags(self):
return self.get('tags').split(',')
def set_tags(self, tags):
self.set('tags', ','.join(tags))
class MCGCache(): class MCGCache():
DIRNAME = '~/.cache/mcg/' DIRNAME = '~/.cache/mcg/'
SIZE_FILENAME = 'size' SIZE_FILENAME = 'size'