Changed the DockerInterface to use a dictionary for containers and added a get_container_by_id method. Added a popup menu and reorganized actions elements in the UI. Also added some logic to the activation and deactivation of ui elements.
This commit is contained in:
parent
f2ca1b36c6
commit
165f079c61
4 changed files with 264 additions and 76 deletions
|
@ -2,6 +2,54 @@
|
|||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.10"/>
|
||||
<object class="GtkActionGroup" id="ContainerActionGroup">
|
||||
<child>
|
||||
<object class="GtkAction" id="start_action">
|
||||
<property name="label" translatable="yes">Start</property>
|
||||
<property name="short_label" translatable="yes">Start</property>
|
||||
<property name="tooltip" translatable="yes">Start a selected stopped container.</property>
|
||||
<property name="stock_id">gtk-media-play</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_start_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="stop_action">
|
||||
<property name="label" translatable="yes">Stop</property>
|
||||
<property name="short_label" translatable="yes">Stop</property>
|
||||
<property name="stock_id">gtk-media-stop</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_stop_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="attach_action">
|
||||
<property name="label" translatable="yes">Attach</property>
|
||||
<property name="short_label" translatable="yes">Attach</property>
|
||||
<property name="stock_id">gtk-jump-to</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_attach_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="log_action">
|
||||
<property name="label" translatable="yes">Log</property>
|
||||
<property name="short_label" translatable="yes">Log</property>
|
||||
<property name="stock_id">gtk-file</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_log_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="delete_container_action">
|
||||
<property name="label" translatable="yes">Delete</property>
|
||||
<property name="short_label" translatable="yes">Delete</property>
|
||||
<property name="tooltip" translatable="yes">Delete the selected container.</property>
|
||||
<property name="stock_id">gtk-delete</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="ContainerList">
|
||||
<columns>
|
||||
<!-- column-name Name -->
|
||||
|
@ -12,6 +60,8 @@
|
|||
<column type="gchararray"/>
|
||||
<!-- column-name Status -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name FullID -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkImage" id="FileStockImage">
|
||||
|
@ -29,6 +79,35 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
</object>
|
||||
<object class="GtkActionGroup" id="ImagesActionGroup">
|
||||
<child>
|
||||
<object class="GtkAction" id="build_action">
|
||||
<property name="label" translatable="yes">Build</property>
|
||||
<property name="short_label" translatable="yes">Build</property>
|
||||
<property name="stock_id">gtk-properties</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_build_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="runimage_action">
|
||||
<property name="label" translatable="yes">Run</property>
|
||||
<property name="short_label" translatable="yes">Run</property>
|
||||
<property name="stock_id">gtk-execute</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_runimage_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="remove_image_action">
|
||||
<property name="label" translatable="yes">Remove</property>
|
||||
<property name="short_label" translatable="yes">Remove</property>
|
||||
<property name="stock_id">gtk-delete</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_remove_image_action_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="ImagesList">
|
||||
<columns>
|
||||
<!-- column-name Repository -->
|
||||
|
@ -48,20 +127,6 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-play</property>
|
||||
</object>
|
||||
<object class="GtkAction" id="attach_action">
|
||||
<property name="label" translatable="yes">Attach</property>
|
||||
<property name="short_label" translatable="yes">Attach</property>
|
||||
<property name="stock_id">gtk-jump-to</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_attach_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="build_action">
|
||||
<property name="label" translatable="yes">Build</property>
|
||||
<property name="short_label" translatable="yes">Build</property>
|
||||
<property name="stock_id">gtk-properties</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_build_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="connect_action">
|
||||
<property name="label" translatable="yes">Connect</property>
|
||||
<property name="short_label" translatable="yes">Connect</property>
|
||||
|
@ -69,13 +134,6 @@
|
|||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_connect_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="log_action">
|
||||
<property name="label" translatable="yes">Log</property>
|
||||
<property name="short_label" translatable="yes">Log</property>
|
||||
<property name="stock_id">gtk-file</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_log_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="preferences_action">
|
||||
<property name="label" translatable="yes">Preferences</property>
|
||||
<property name="short_label" translatable="yes">Preferences</property>
|
||||
|
@ -91,35 +149,6 @@
|
|||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_refresh_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="remove_image_action">
|
||||
<property name="label" translatable="yes">Remove</property>
|
||||
<property name="short_label" translatable="yes">Remove</property>
|
||||
<property name="stock_id">gtk-delete</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_remove_image_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="runimage_action">
|
||||
<property name="label" translatable="yes">Run</property>
|
||||
<property name="short_label" translatable="yes">Run</property>
|
||||
<property name="stock_id">gtk-execute</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_runimage_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="start_action">
|
||||
<property name="label" translatable="yes">Start</property>
|
||||
<property name="short_label" translatable="yes">Start</property>
|
||||
<property name="tooltip" translatable="yes">Start a selected stopped container.</property>
|
||||
<property name="stock_id">gtk-media-play</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_start_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="stop_action">
|
||||
<property name="label" translatable="yes">Stop</property>
|
||||
<property name="short_label" translatable="yes">Stop</property>
|
||||
<property name="stock_id">gtk-media-stop</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="activate" handler="on_stop_action_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkWindow" id="MainWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Stevedore</property>
|
||||
|
@ -285,6 +314,35 @@
|
|||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="DeleteContainerButton">
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">delete_container_action</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="yalign">0.56999999284744263</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -306,8 +364,11 @@
|
|||
<property name="search_column">0</property>
|
||||
<property name="show_expanders">False</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<signal name="button-press-event" handler="on_ContainerListView_button_press_event" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection1"/>
|
||||
<object class="GtkTreeSelection" id="container_view_selection">
|
||||
<signal name="changed" handler="on_container_view_selection_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ContainerName">
|
||||
|
@ -414,23 +475,6 @@
|
|||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="RemoveImageButton">
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">remove_image_action</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="RunImageButton">
|
||||
<property name="label">gtk-execute</property>
|
||||
|
@ -442,12 +486,40 @@
|
|||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="RemoveImageButton">
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">remove_image_action</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
|
18
res/ui_builder.xml
Normal file
18
res/ui_builder.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<ui>
|
||||
<popup name='ContainerStoppedPopup'>
|
||||
<menuitem action='start_action' />
|
||||
<menuitem action='log_action' />
|
||||
<separator />
|
||||
<menuitem action='delete_container_action' />
|
||||
</popup>
|
||||
<popup name='ContainerStartedPopup'>
|
||||
<menuitem action='stop_action' />
|
||||
<menuitem action='attach_action' />
|
||||
<menuitem action='log_action' />
|
||||
</popup>
|
||||
<popup name='ImagePopup'>
|
||||
<menuitem action='build_action' />
|
||||
<menuitem action='runimage_action' />
|
||||
<menuitem action='remove_image_action' />
|
||||
</popup>
|
||||
</ui>
|
|
@ -60,7 +60,7 @@ class DockerContainer(object):
|
|||
self.command = command
|
||||
self.created = created
|
||||
self.names = self.filter_names(names)
|
||||
self.status = "Unknown"
|
||||
self.status = DockerContainer.UNKNOWN
|
||||
self.time_elapsed = 0
|
||||
self.ports = []
|
||||
|
||||
|
@ -200,7 +200,7 @@ class DockerInterface(object):
|
|||
"""
|
||||
Ask our docker server the containers created and their status
|
||||
"""
|
||||
self.containers = []
|
||||
self.containers = dict()
|
||||
if self.client is not None:
|
||||
containers = self.client.containers(all = True)
|
||||
for container in containers:
|
||||
|
@ -211,11 +211,21 @@ class DockerInterface(object):
|
|||
names = container['Names'])
|
||||
|
||||
container_object.status_from_string(container['Status'])
|
||||
self.containers.append(container_object)
|
||||
self.containers[container['Id']] = container_object
|
||||
|
||||
else:
|
||||
raise DockerNotConnectedException()
|
||||
|
||||
|
||||
def get_container_by_id(self, container_id):
|
||||
"""
|
||||
Returns the container that matched container_id
|
||||
"""
|
||||
if self.client is None:
|
||||
raise DockerNotConnectedException()
|
||||
|
||||
return self.containers.get(container_id, None)
|
||||
|
||||
def build(self, path, tag):
|
||||
"""
|
||||
Creates a new docker image from a Dockerfile in the specified path
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# Generated with glade2py script
|
||||
# glade2py script can be found at hocr web site http://hocr.berlios.de
|
||||
|
||||
from gi.repository import Gtk, Gio
|
||||
from gi.repository import Gtk, Gdk, Gio
|
||||
from pkg_resources import resource_string
|
||||
from docker_iface import DockerInterface, DockerImage, DockerContainer, DockerNotConnectedException
|
||||
|
||||
|
@ -35,19 +35,31 @@ class MainWindow(Gtk.Application):
|
|||
|
||||
# create widget tree ...
|
||||
self.builder = Gtk.Builder()
|
||||
self.ui_manager = Gtk.UIManager()
|
||||
try:
|
||||
self.builder.add_from_file(resource_string(__name__, 'stevedore.glade'))
|
||||
self.ui_manager.add_ui_from_file(resource_string(__name__, 'ui_builder.xml'))
|
||||
|
||||
except:
|
||||
self.builder.add_from_file('../res/stevedore.glade')
|
||||
self.ui_manager.add_ui_from_file('../res/ui_builder.xml')
|
||||
|
||||
# connect handlers
|
||||
self.builder.connect_signals(self)
|
||||
self.ui_manager.insert_action_group(self.builder.get_object('ContainerActionGroup'))
|
||||
self.ui_manager.insert_action_group(self.builder.get_object('ImagesActionGroup'))
|
||||
|
||||
# Prepare certain widgets
|
||||
self.status_bar = self.builder.get_object('AppStatus')
|
||||
self.status_context_id = self.status_bar.get_context_id('main_app')
|
||||
self.builder.get_object('StartButton').set_sensitive(False)
|
||||
self.builder.get_object('StopButton').set_sensitive(False)
|
||||
self.builder.get_object('AttachButton').set_sensitive(False)
|
||||
self.builder.get_object('LogButton').set_sensitive(False)
|
||||
self.builder.get_object('DeleteContainerButton').set_sensitive(False)
|
||||
|
||||
# Add window to the App and show it
|
||||
self.window = self.builder.get_object('MainWindow')
|
||||
self.status_bar = self.builder.get_object('AppStatus')
|
||||
self.status_context_id = self.status_bar.get_context_id('main_app')
|
||||
self.add_window(self.window)
|
||||
self.window.show()
|
||||
self.set_app_status(u'Not connected to Docker server.')
|
||||
|
@ -74,12 +86,14 @@ class MainWindow(Gtk.Application):
|
|||
image_list.clear()
|
||||
|
||||
# And now we populate them back
|
||||
for container in self.docker.containers:
|
||||
for container_index in self.docker.containers:
|
||||
container = self.docker.get_container_by_id(container_index)
|
||||
status = container.return_status_string()
|
||||
container_list.append(row = [container.names[0],
|
||||
unicode(container.image),
|
||||
unicode(container.container_id)[:12],
|
||||
status])
|
||||
status,
|
||||
unicode(container.container_id)])
|
||||
|
||||
for image in self.docker.images:
|
||||
size_text = self.size_to_human(image.size)
|
||||
|
@ -214,6 +228,80 @@ class MainWindow(Gtk.Application):
|
|||
"""
|
||||
print "Not implemented: on_runimage_action_activate"
|
||||
|
||||
def on_ContainerListView_button_press_event(self, obj, event = None):
|
||||
"""
|
||||
This hook checks the mouse interaction with the ContainerListView
|
||||
"""
|
||||
if event is not None:
|
||||
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
|
||||
container_view = self.builder.get_object('ContainerListView')
|
||||
selection = container_view.get_selection()
|
||||
model, selected = selection.get_selected()
|
||||
# selection is a treeiter
|
||||
if selected is not None:
|
||||
selected_container_id = model[selected][4]
|
||||
container = self.docker.get_container_by_id(selected_container_id)
|
||||
|
||||
if container is not None:
|
||||
if container.status == DockerContainer.EXITED:
|
||||
popup = self.ui_manager.get_widget('/ContainerStoppedPopup')
|
||||
|
||||
elif container.status == DockerContainer.UP:
|
||||
popup = self.ui_manager.get_widget('/ContainerStartedPopup')
|
||||
|
||||
else:
|
||||
popup = self.ui_manager.get_widget('/ContainerStoppedPopup')
|
||||
|
||||
popup.popup(None, None, None, None, event.button, event.time)
|
||||
return True
|
||||
|
||||
def on_container_view_selection_changed(self, selection):
|
||||
"""
|
||||
We control which element is selected on the ContainerListView to enable and disable
|
||||
certain button actions
|
||||
"""
|
||||
start_button = self.builder.get_object('StartButton')
|
||||
stop_button = self.builder.get_object('StopButton')
|
||||
attach_button = self.builder.get_object('AttachButton')
|
||||
log_button = self.builder.get_object('LogButton')
|
||||
delete_container_button = self.builder.get_object('DeleteContainerButton')
|
||||
|
||||
model, treeiter = selection.get_selected()
|
||||
if treeiter is not None:
|
||||
container_id = model[treeiter][4]
|
||||
container = self.docker.get_container_by_id(container_id)
|
||||
|
||||
if container.status == DockerContainer.UP:
|
||||
start_button.set_sensitive(False)
|
||||
stop_button.set_sensitive(True)
|
||||
attach_button.set_sensitive(True)
|
||||
log_button.set_sensitive(True)
|
||||
delete_container_button.set_sensitive(False)
|
||||
|
||||
elif container.status == DockerContainer.EXITED:
|
||||
start_button.set_sensitive(True)
|
||||
stop_button.set_sensitive(False)
|
||||
attach_button.set_sensitive(False)
|
||||
log_button.set_sensitive(True)
|
||||
delete_container_button.set_sensitive(True)
|
||||
|
||||
else:
|
||||
start_button.set_sensitive(False)
|
||||
stop_button.set_sensitive(False)
|
||||
attach_button.set_sensitive(False)
|
||||
log_button.set_sensitive(True)
|
||||
delete_container_button.set_sensitive(True)
|
||||
|
||||
else:
|
||||
start_button.set_sensitive(False)
|
||||
stop_button.set_sensitive(False)
|
||||
attach_button.set_sensitive(False)
|
||||
log_button.set_sensitive(False)
|
||||
delete_container_button.set_sensitive(False)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# run main loop
|
||||
def main():
|
||||
|
|
Loading…
Reference in a new issue