Compare commits

...

7 commits

3 changed files with 490 additions and 7 deletions

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkActionGroup" id="ContainerActionGroup">
@ -128,6 +128,206 @@
<property name="can_focus">False</property>
<property name="stock">gtk-media-play</property>
</object>
<object class="GtkWindow" id="PreferencesWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Preferences</property>
<signal name="delete-event" handler="on_PreferencesWindow_delete_event" swapped="no"/>
<child>
<object class="GtkBox" id="PrefsBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFrame" id="ConnectionFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label_xalign">0</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">12</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Host:</property>
<property name="justify">right</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="HostnameEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="editable">False</property>
<property name="placeholder_text" translatable="yes">Docker Server Hostname</property>
<signal name="changed" handler="on_HostnameEntry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Port:</property>
<property name="justify">right</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="PortEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="editable">False</property>
<property name="placeholder_text" translatable="yes">Docker Server Port</property>
<property name="input_purpose">number</property>
<signal name="changed" handler="on_PortEntry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="LocalCheckBox">
<property name="label" translatable="yes">Connect to local server through Unix socket</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_LocalCheckBox_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Docker Server Connection Preferences</property>
<property name="angle">0.27000000000000002</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="PrefsButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="baseline_position">bottom</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="PrefsCloseButton">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_PrefsCloseButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkAction" id="connect_action">
<property name="label" translatable="yes">Connect</property>
<property name="short_label" translatable="yes">Connect</property>

173
src/prefs.py Normal file
View file

@ -0,0 +1,173 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import os
import os.path
class Preferences(dict):
"""
This class allows us to control and maintain preferences and
store them
"""
def __init__(self):
self._options = dict()
self._header = "# Stevedore configuration file\n# This file may be overwritten by the program itself\n"
home_directory = os.path.expanduser('~')
self._directory = os.path.join(home_directory, '.config/stevedore')
self._filename = 'main.conf'
try:
self.load_preferences()
except IOError as e:
# for debuggin purposes
print "Error loading preferences file: " + str(e)
self.create_preferences()
def load_preferences(self):
"""
Loads the preferences from the default filename
"""
with open(os.path.join(self._directory, self._filename), 'r') as f:
for line in f:
if line[0] != '#':
try:
self._set_config_from_string(line)
except Exception as e:
# for debugging purposes
print "Problem reading the file: " + str(e)
# We'd rather ignore the problems and keep loading
pass
def create_preferences(self):
"""
If we don't have any preferences file, we create it
"""
if not os.path.isdir(self._directory):
# We create the directory
os.mkdir(self._directory)
if not os.path.exists(os.path.join(self._directory, self._filename)):
self.set_default_options()
self.save_preferences()
def set_default_options(self):
"""
Set preferences to the defaults
"""
self._options['localhost'] = True
self._options['host'] = 'localhost'
self._options['port'] = 0
self._header = "# Default options for stevedore.\n# This file may be overwritten from the program itself\n"
def save_preferences(self):
"""
Stores the preferences into a file
"""
try:
prefs_file = open(os.path.join(self._directory, self._filename), 'w')
except IOError as e:
# Debugging
print "Creating new preferences file"
self.create_preferences()
prefs_file = open(os.path.join(self._directory, self._filename), 'w')
prefs_file.write(self._header + "\n")
for key in self._options:
line = self._get_config_string(key)
if line != "":
prefs_file.write(line + "\n")
prefs_file.close()
def _get_config_string(self, key):
"""
Turns an option key into a string for the config file
"""
value = self._options.get(key, None)
if value is None:
return ""
else:
return key + " = " + str(value)
def _set_config_from_string(self, config_line):
"""
Turns an option line into an option
"""
line_split = config_line.split('=')
try:
key = line_split[0].strip()
val = line_split[1].strip()
except:
return
if val.isdigit():
value = int(val)
elif val == 'True':
value = True
elif val == 'False':
value = False
else:
value = val
self._options[key] = value
def __setitem__(self, key, value):
"""
Safe option setting
"""
if type(value) == str or type(value) == unicode:
if value == 'True':
value = True
elif value == 'False':
value = False
elif value.isdigit():
value = int(value)
self._options[key] = value
def __getitem__(self, key):
"""
Return an option value safely. None if it does not exist.
"""
return self._options.get(key, None)
def __len__(self):
"""
Return the number of current options
"""
return len(self._options)
def __delitem__(self, key):
"""
Delete an option
"""
try:
del(self._options[key])
except:
pass

View file

@ -20,12 +20,14 @@
from gi.repository import Gtk, Gdk, Gio
from pkg_resources import resource_string
from docker_iface import DockerInterface, DockerImage, DockerContainer, DockerNotConnectedException
from prefs import Preferences
import time
class MainWindow(Gtk.Application):
class MainApplication(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self, application_id = "apps.gnome.stevedore",
flags = Gio.ApplicationFlags.FLAGS_NONE)
@ -58,6 +60,9 @@ class MainWindow(Gtk.Application):
self.builder.get_object('LogButton').set_sensitive(False)
self.builder.get_object('DeleteContainerButton').set_sensitive(False)
# Get the preferences ready
self.preferences = Preferences()
# Add window to the App and show it
self.window = self.builder.get_object('MainWindow')
self.add_window(self.window)
@ -149,13 +154,55 @@ class MainWindow(Gtk.Application):
self.status_bar.push(self.status_context_id, message)
def get_preferences_from_window(self):
"""
Gets the current Preferences window widgets and saves the options
"""
localhost_checkbox = self.builder.get_object('LocalCheckBox')
hostname_entry = self.builder.get_object('HostnameEntry')
port_entry = self.builder.get_object('PortEntry')
if localhost_checkbox.get_active():
self.preferences['localhost'] = True
self.preferences['host'] = 'localhost'
self.preferences['port'] = 0
else:
self.preferences['localhost'] = False
self.preferences['host'] = hostname_entry.get_text()
if port_entry.get_text() != '':
self.preferences['port'] = int(port_entry.get_text())
# Events and "natural" callbacks
def on_MainWindow_delete_event(self, obj, event = None):
"""
The main window is deleted
"""
pass
self.preferences.save_preferences()
def on_PreferencesWindow_delete_event(self, obj, event = None):
"""
The Preferences window has been closed by clicking the close window
button from the window manager
obj --
event --
"""
preferences_window = self.builder.get_object('PreferencesWindow')
preferences_window.hide()
return True
def on_PrefsCloseButton_clicked(self, obj, event = None):
"""
The close button at the preferences has been pressed
obj --
event --
"""
preferences_window = self.builder.get_object('PreferencesWindow')
preferences_window.hide()
### Action callbacks ###
@ -189,8 +236,34 @@ class MainWindow(Gtk.Application):
"""
We've been asked for the preferences window
"""
# TODO
print "Not implemented: on_preferences_action_activate"
preferences_window = self.builder.get_object('PreferencesWindow')
localhost_checkbox = self.builder.get_object('LocalCheckBox')
hostname_entry = self.builder.get_object('HostnameEntry')
port_entry = self.builder.get_object('PortEntry')
# Set up the window to the current preferences before showing it up
if self.preferences['localhost']:
# We're connecting to a local instance
localhost_checkbox.set_active(True)
hostname_entry.set_text('')
hostname_entry.set_editable(False)
port_entry.set_text('')
port_entry.set_editable(False)
else:
# We're connecting to a remote instance
localhost_checkbox.set_active(False)
hostname_entry.set_text(self.preferences['host'])
hostname_entry.set_editable(True)
port_entry.set_text(unicode(self.preferences['port']))
port_entry.set_editable(True)
# Now we show up our preferences window
preferences_window.show()
def on_refresh_action_activate(self, obj, event = None):
"""
@ -344,11 +417,48 @@ class MainWindow(Gtk.Application):
log_button.set_sensitive(False)
delete_container_button.set_sensitive(False)
# Preferences window callbacks
def on_LocalCheckBox_toggled(self, obj, data = None):
"""
The checkbox has been changed
"""
localhost_checkbox = self.builder.get_object('LocalCheckBox')
hostname_entry = self.builder.get_object('HostnameEntry')
port_entry = self.builder.get_object('PortEntry')
if localhost_checkbox.get_active():
hostname_entry.set_text('')
hostname_entry.set_editable(False)
port_entry.set_text('')
port_entry.set_editable(False)
else:
hostname_entry.set_text(self.preferences['host'])
hostname_entry.set_editable(True)
port_entry.set_text(unicode(self.preferences['port']))
port_entry.set_editable(True)
self.get_preferences_from_window()
def on_PortEntry_changed(self, obj, data = None):
"""
The port entry has been changed
"""
self.get_preferences_from_window()
def on_HostnameEntry_changed(self, obj, data = None):
"""
The hostname entry has been changed
"""
self.get_preferences_from_window()
# run main loop
def main():
main_window = MainWindow()
main_window.run(None)
main_app = MainApplication()
main_app.run(None)
if __name__ == "__main__":
main()