This is the first working code for the GTK front end. It is still in
development.
--- /dev/null
+++ b/lib/mp3togo.glade
@@ -0,0 +1,1120 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="ImportDialog">
+ <property name="title" translatable="yes" context="yes">Import Playlist</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">320</property>
+ <property name="default_height">260</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog1-vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog1-action_area">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="ImportGo">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Import</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ImportCancel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Cancel</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_ImportCancel" last_modification_time="Mon, 05 Jun 2006 01:35:33 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="ImportTitle">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Import Playlist from Application</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="ImportXMMS">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Import from XMMS session</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ImportXMMS_toggled" last_modification_time="Sun, 04 Jun 2006 21:34:25 GMT"/>
+ <signal name="clicked" handler="on_ImportXMMS_clicked" last_modification_time="Sun, 04 Jun 2006 21:46:21 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="XMMSSession">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="ImportAmarok">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Import from amaroK</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">ImportXMMS</property>
+ <signal name="toggled" handler="on_ImportAmarok_toggled" last_modification_time="Sun, 04 Jun 2006 21:36:56 GMT"/>
+ <signal name="clicked" handler="on_ImportAmarok_clicked" last_modification_time="Sun, 04 Jun 2006 21:46:12 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">12</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="MainWindow">
+ <property name="title" translatable="yes" context="yes">mp3togo</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">620</property>
+ <property name="default_height">400</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <signal name="destroy" handler="on_MainWindow_destroy" last_modification_time="Sun, 04 Jun 2006 19:28:09 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="vboxWhole">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vboxTitle">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="Title">
+ <property name="height_request">15</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">mp3togo</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">True</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="Configure">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Settings</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_Configure" last_modification_time="Sun, 04 Jun 2006 21:52:39 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="Exit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Quit</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_Exit" last_modification_time="Sun, 04 Jun 2006 19:45:04 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHSeparator" id="hseparatorTop">
+ <property name="height_request">2</property>
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHPaned" id="hpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Playlist</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="border_width">2</property>
+ <property name="width_request">300</property>
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="PlayListList">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">True</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonboxSelect">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="SelectAll">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_SelectAll" last_modification_time="Tue, 06 Jun 2006 07:49:11 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">All</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="SelectNone">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_SelectNone" last_modification_time="Tue, 06 Jun 2006 07:49:22 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">None</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="SelectInvert">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_SelectInvert" last_modification_time="Tue, 06 Jun 2006 07:49:32 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Invert</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="button7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Remove Selected</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_PlaylistRemove" last_modification_time="Mon, 05 Jun 2006 02:45:55 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Add Files</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_PlaylistAddFiles" last_modification_time="Sun, 04 Jun 2006 20:45:36 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Import from App</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_PlaylistImport" last_modification_time="Sun, 04 Jun 2006 21:18:48 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Player</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="Placeholder">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Not implemented</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHSeparator" id="hseparator1">
+ <property name="height_request">2</property>
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vboxStatus">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkLabel" id="CurrentFile">
+ <property name="width_request">420</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hboxBottom">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vboxProgress">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="StatusText">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkProgressBar" id="Progress">
+ <property name="height_request">20</property>
+ <property name="visible">True</property>
+ <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
+ <property name="fraction">0</property>
+ <property name="pulse_step">0.10000000149</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="PauseStop">
+ <property name="height_request">30</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkButton" id="Start">
+ <property name="visible">True</property>
+ <property name="label">gtk-convert</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_Start" last_modification_time="Tue, 06 Jun 2006 08:06:47 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="Pause">
+ <property name="visible">True</property>
+ <property name="label">gtk-media-pause</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="Abort">
+ <property name="visible">True</property>
+ <property name="label">gtk-media-stop</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="SettingsDialog">
+ <property name="title" translatable="yes" context="yes">mp3togo settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">320</property>
+ <property name="default_height">260</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog2-vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog2-action_area">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="SettingsSave">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Save</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="SettingsCancel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="yes">Cancel</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vboxSettings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkFileChooserDialog" id="AddFilesSelector">
+ <property name="visible">True</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="select_multiple">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="title" translatable="yes">Add Files or Playlists</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">24</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-open</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
--- /dev/null
+++ b/lib/mp3togo.gladep
@@ -0,0 +1,8 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+ <name>mp3togo</name>
+ <program_name>mp3togo</program_name>
+ <gnome_support>FALSE</gnome_support>
+</glade-project>
--- a/mp3togo/__init__.py
+++ b/mp3togo/__init__.py
@@ -21,5 +21,5 @@
# __all__ = ('converter', 'main', 'options', 'setup')
-version = '0.5.3'
+version = '0.6.0'
--- a/mp3togo/cluster.py
+++ b/mp3togo/cluster.py
@@ -97,23 +97,13 @@ def slave(opts):
def initialize(ropts):
"""Integrate remote options into local opts"""
- # of = file('/home/sim/temp/2go/cluster/opts-slave', 'w')
-# for key in ropts.keys():
-# if opts.has_key(key):
-# opts[key] = ropts[key]
-# # of.write("%s: %s\n" % (key, opts[key]))
-# else:
-# return None
- # of.close()
- st = ropts['pickle']
- opts._d = cPickle.loads(st)
-
- opts['verbosity'] = 0
- of = file('/home/sim/temp/2go/cluster/opts-slave', 'w')
- for key in opts.keys():
- of.write("%s: %s\n" % (key, opts[key]))
- of.close()
- return "SLAVE: ready"
+ try:
+ st = ropts['pickle']
+ opts._d = cPickle.loads(st)
+ opts['verbosity'] = 0
+ return "SLAVE: ready"
+ except:
+ return None
def perform(rotps):
"""Run the work unit and watch progress"""
@@ -221,8 +211,10 @@ class Boss:
self.pid, self.fd1 = pty.fork()
if self.pid == 0:
args = r_schema.replace('%h', host)
- args += " mp3togo --cluster-slave True"
- #args += " test-mp3togo --cluster-slave True"
+ if self.opts.argv:
+ args += " " + self.opts.argv[0] + " --cluster-slave True"
+ else:
+ args += " mp3togo --cluster-slave True"
args = args.split()
os.execvp(args[0], args)
else:
@@ -267,6 +259,7 @@ class Boss:
self.files.push(self.current, front=True)
raise StopIteration
yield ('Not Ready', 'Not Ready', 0)
+ # Roll back and try to start again self = Boss(yada, ...)
continue
self.rf.flush()
for line in inp.split('\n'):
@@ -289,12 +282,12 @@ class Boss:
return
self.wf.write('file=%s\n' % self.current)
self.wf.write(EOT)
- start = time.time()
+ self.start = time.time()
percent = 0.0
if EOR.replace('\n', '') == line:
if self.current:
yield (self.current, 'Finished',
- float(time.time() - start))
+ float(time.time() - self.start))
next()
break
elif line.startswith('Progress:'):
--- a/mp3togo/conf.py
+++ b/mp3togo/conf.py
@@ -73,11 +73,14 @@ class Options(options.Options):
"""Subclass options.Options and fill in application specific
information."""
def __init__(self, argv=None, conffile=None, readconf=True):
- options.Options.__init__(self, '~/.mp3togo')
+ self.argv = argv
+ options.Options.__init__(self, absfile('~/.mp3togo'))
# Options to add:
# ((name, short option, long option, default value, hook, help text), ...)
self._set += [
+ ('gui', 'X', 'gui-mode', False, None,
+ '''Start mp3togo GTK interface.'''),
('brwarning', 't', 'file-tag', '.2go', None,
'''A string appended to the name of the file to indicate it has been recoded.'''),
('tempdir', 'w', 'work-dir', '/tmp', self._absfile,
--- /dev/null
+++ b/mp3togo/gui/__init__.py
@@ -0,0 +1,23 @@
+#
+# mp3togo Portable Music Manager
+#
+# PyGTK interface sub package
+#
+# Copyright 2006: Simeon Veldstra <reallifesim@gmail.com>
+#
+# 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 2
+# 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.
+
+
--- /dev/null
+++ b/mp3togo/gui/filewindow.py
@@ -0,0 +1,50 @@
+# - gui/filewindow.py --
+# GTK user interface - File selection window
+#
+# This file is part of mp3togo
+#
+# (c) Simeon Veldstra 2006 <reallifesim@gmail.com>
+#
+# This software is free.
+#
+# 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 may redistribute this program under the terms of the
+# GNU General Public Licence version 2
+# Available in this package or at http://www.fsf.org
+
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+ import gtk
+ import gtk.glade
+ import gobject
+except:
+ print "GTK not present! mp3togo GTK GUI requires python-gtk2 and python-glade2"
+ sys.exit(1)
+
+import sys
+import os
+
+import mp3togo.gui.gutil as gutil
+
+class AddFilesSelector:
+ """File and playlist selector"""
+
+ def __init__(self, opts):
+ self.opts = opts
+
+ def run(self):
+ gladefile = gutil.find_glade_xml(self.opts)
+ self.wTree = gtk.glade.XML(gladefile, "AddFilesSelector")
+ self.dlg = self.wTree.get_widget("AddFilesSelector")
+
+ result = self.dlg.run()
+ names = self.dlg.get_filenames()
+ self.dlg.destroy()
+ return names
+
--- /dev/null
+++ b/mp3togo/gui/gutil.py
@@ -0,0 +1,35 @@
+# - gutil.py --
+# GTK user interface utility functions
+
+# This file is part of mp3togo
+
+# Convert audio files to play on a mp3 player
+#
+# (c) Simeon Veldstra 2006 <reallifesim@gmail.com>
+#
+# This software is free.
+#
+# 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 may redistribute this program under the terms of the
+# GNU General Public Licence version 2
+# Available in this package or at http://www.fsf.org
+
+import os
+import sys
+
+import mp3togo.conf as conf
+
+def find_glade_xml(opts):
+ """Return a path to the glade xml file."""
+ if opts.argv and opts.argv[0] != "mp3togo":
+ xml = os.path.split(conf.__file__)[0]
+ xml = os.path.split(xml)[0]
+ xml = os.path.join(xml, 'lib/mp3togo.glade')
+ else:
+ xml = os.path.join(sys.prefix, 'lib/mp3togo/mp3togo.glade')
+ return xml
+
--- /dev/null
+++ b/mp3togo/gui/importwindow.py
@@ -0,0 +1,77 @@
+# - gui/importwindow.py --
+# GTK user interface - Import from jukebox application window
+#
+# This file is part of mp3togo
+#
+# (c) Simeon Veldstra 2006 <reallifesim@gmail.com>
+#
+# This software is free.
+#
+# 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 may redistribute this program under the terms of the
+# GNU General Public Licence version 2
+# Available in this package or at http://www.fsf.org
+
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+ import gtk
+ import gtk.glade
+ import gobject
+except:
+ print "GTK not present! mp3togo GTK GUI requires python-gtk2 and python-glade2"
+ sys.exit(1)
+
+import mp3togo.gui.gutil as gutil
+
+
+class ImportDialog:
+ """Import playlists from jukebox apps."""
+
+ def __init__(self, opts):
+ self.current = "XMMS"
+
+ gladefile = gutil.find_glade_xml(opts)
+ self.wTree = gtk.glade.XML(gladefile, "ImportDialog")
+ self.dlg = self.wTree.get_widget("ImportDialog")
+
+ callbacks = {
+ "on_ImportXMMS_toggled": (self.change, "XMMS"),
+ "on_ImportAmarok_toggled": (self.change, "amaroK"),
+ "on_ImportCancel": (self.change, ""),
+ }
+ self.wTree.signal_autoconnect(callbacks)
+
+ # Shade out jukeboxes that are not supported on this machine
+ if not opts.mod['xmms']:
+ if self.current.startswith('XMMS'):
+ self.current = ''
+ rbut = self.wTree.get_widget('ImportXMMS')
+ spinner = self.wTree.get_widget('XMMSSession')
+ rbut.set_active(False)
+ spinner.set_editable(False)
+
+ if not opts.bin['dcop']:
+ rbut = self.wTree.get_widget('ImportAmarok')
+ rbut.set_active(False)
+
+ def change(self, obj, arg):
+ self.current = arg
+
+ def run(self):
+ """Show the Import from Jukebox dialog."""
+ self.dlg.run()
+ name = self.current
+ if name == 'XMMS':
+ spinner = self.wTree.get_widget('XMMSSession')
+ name += ':' + str(int(spinner.get_value()))
+ self.dlg.destroy()
+ return name
+
+
+
--- /dev/null
+++ b/mp3togo/gui/mainwindow.py
@@ -0,0 +1,347 @@
+# - gui/mainwindow.py --
+# GTK user interface - Main application window
+#
+# This file is part of mp3togo
+#
+# (c) Simeon Veldstra 2006 <reallifesim@gmail.com>
+#
+# This software is free.
+#
+# 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 may redistribute this program under the terms of the
+# GNU General Public Licence version 2
+# Available in this package or at http://www.fsf.org
+
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+ import gtk
+ import gtk.glade
+ import gobject
+except:
+ print "GTK not present! mp3togo GTK GUI requires python-gtk2 and python-glade2"
+ sys.exit(1)
+
+import sys
+import os
+import time
+import threading
+
+import mp3togo.util as util
+import mp3togo.conf as conf
+import mp3togo.filelist as filelist
+import mp3togo.pool as pool
+import mp3togo.track as track
+import mp3togo.task as task
+import mp3togo.cache as cache
+import mp3togo.cluster as cluster
+
+import mp3togo.gui.gutil as gutil
+import mp3togo.gui.filewindow as filewindow
+import mp3togo.gui.importwindow as importwindow
+
+### Playlist Model: ['running', True, False, '/foo/bar/one.mp3'] ###
+STATUS = 0
+ABLE = 1
+SELECTED = 2
+FILE = 3
+NAME = 4
+
+
+class MainWind:
+ """The GUI Front end"""
+
+ def __init__(self, opts):
+ self.opts = opts
+ self.list = filelist.FileList(opts)
+ self.pool = pool.Pool(opts)
+ self.fails = {}
+ self.gang = []
+ self.gladexml = gutil.find_glade_xml(opts)
+
+ self.wTree = gtk.glade.XML(self.gladexml, "MainWindow")
+
+ # Create the playlist list widget
+ self.playlistmodel = gtk.ListStore(str, bool, bool, str, str)
+ self.playlistview = self.wTree.get_widget("PlayListList")
+ column = gtk.TreeViewColumn('Done',
+ gtk.CellRendererText(),
+ text=STATUS)
+ self.playlistview.append_column(column)
+ toggle = gtk.CellRendererToggle()
+ toggle.set_property('activatable', True)
+ def cell_toggle(renderer, path, data):
+ new = self.playlistmodel[path]
+ new[SELECTED] = not new[SELECTED]
+ self.playlistmodel[path] = new
+ toggle.connect("toggled", cell_toggle, None)
+ column = gtk.TreeViewColumn('X',
+ toggle,
+ activatable=ABLE,
+ active=SELECTED)
+ self.playlistview.append_column(column)
+ column = gtk.TreeViewColumn('File',
+ gtk.CellRendererText(),
+ text=NAME)
+ column.set_sort_column_id(FILE)
+ self.playlistview.append_column(column)
+ self.playlistview.set_model(self.playlistmodel)
+
+ self.tips = gtk.Tooltips()
+
+ callbacks = {
+ "on_Exit": self.exit,
+ "on_MainWindow_destroy": self.exit,
+ "on_PlaylistAddFiles": self.add_files,
+ "on_PlaylistImport": self.import_files,
+ "on_PlaylistRemove": self.update_playlist,
+ "on_SelectAll": self.select_all_playlist,
+ "on_SelectNone": self.select_none_playlist,
+ "on_SelectInvert": self.select_invert_playlist,
+ "on_Configure": self.configure,
+ "on_Start": self.convert,
+ }
+ self.wTree.signal_autoconnect(callbacks)
+
+ # Set up worker processes:
+ self.workers = [('mp3togoGTK', '')]
+
+ self.window = self.wTree.get_widget("MainWindow")
+ if self.window:
+ self.window.show()
+
+ def update_playlist(self, obj=None):
+ # Remove selected files
+ def match_selected(model, path, iter, data):
+ if model.get_value(iter, SELECTED):
+ data.append(path)
+ paths = []
+ self.playlistmodel.foreach(match_selected, paths)
+ paths.reverse()
+ for path in paths:
+ iter = self.playlistmodel.get_iter(path)
+ name = self.playlistmodel.get_value(iter, FILE)
+ self.list.removefile(name)
+ self.playlistmodel.remove(iter)
+
+ # Add new files to the widget
+ # Assumes new files are always added to the end of a FileList.
+ files = self.list._list[:]
+ files.reverse()
+
+ # This is stupid:
+ addfiles = []
+ while files and files[0] not in [x[FILE] for x in self.playlistmodel]:
+ addfiles.insert(0, files[0])
+ del files[0]
+ for f in addfiles:
+ name = os.path.basename(f)
+ self.playlistmodel.append(['',
+ True,
+ False,
+ f,
+ name])
+
+ def start_file(self, fname):
+ """Start work on a file"""
+ for row in self.playlistmodel:
+ if row[FILE] == fname:
+ row[SELECTED] = False
+ row[ABLE] = False
+ row[STATUS] = ' ->'
+
+ def unstart_file(self, fname):
+ """File started but didn't finish. probably failed."""
+ for row in self.playlistmodel:
+ if row[FILE] == fname:
+ row[ABLE] = True
+ row[STATUS] = 'Failed'
+
+ def finish_file(self, fname, elapsed="done"):
+ """File is done"""
+ for row in self.playlistmodel:
+ if row[FILE] == fname:
+ row[ABLE] = True
+ row[STATUS] = elapsed
+
+ def select_all_playlist(self, obj=None):
+ """Select all"""
+ for row in self.playlistmodel:
+ row[SELECTED] = True
+
+ def select_none_playlist(self, obj=None):
+ """Select None"""
+ for row in self.playlistmodel:
+ row[SELECTED] = False
+
+ def select_invert_playlist(self, obj=None):
+ """Invert selection"""
+ for row in self.playlistmodel:
+ row[SELECTED] = not row[SELECTED]
+
+ def add_files(self, obj):
+ """Callback to spawn fileselector"""
+ child = filewindow.AddFilesSelector(self.opts)
+ result = child.run()
+ self.list.addfiles(result)
+ self.update_playlist()
+
+ def import_files(self, obj):
+ """callback to spawn file importer"""
+ child = importwindow.ImportDialog(self.opts)
+ result = child.run()
+ try:
+ # Move this into the list class
+ if result.startswith('XMMS'):
+ self.list.addXMMS(session=int(result.split(':')[1]))
+ elif result.startswith('amaroK'):
+ self.list.addAmarok()
+ except:
+ print "exception"
+ self.update_playlist()
+
+ def convert(self, obj=None):
+ """Start the conversion"""
+ if not self.list._list:
+ return
+ # Set up cache
+ cooked = None
+
+ # Check for sanity
+ pass
+
+ for host in self.workers:
+ master = cluster.Boss(host[0],
+ self.list,
+ self.fails,
+ self.opts,
+ host[1])
+ self.gang.append({'boss': master,
+ 'poll': master.poll(),
+ 'file': ''})
+
+ def refresh_callback(self):
+ """Monitor the workers"""
+ if self.gang:
+ for slave in self.gang[:]:
+ try:
+ status = slave['poll'].next()
+ print status
+ except StopIteration:
+ if slave['file']:
+ self.finish_file(slave['file'])
+ del self.gang[self.gang.index(slave)]
+ break
+ if status[1] == 'Subtask Failed':
+ if slave['file']:
+ self.unstart_file(slave['file'])
+ self.set_status('Task failed')
+ break
+ if status[1] == 'Not Ready':
+ break
+ if status[1] == 'Finished':
+ self.set_progress(0.0)
+ if slave['file']:
+ ts = util.format_time(status[2])
+ self.finish_file(slave['file'], ts)
+ self.set_status('Finished')
+ slave['file'] = ''
+ break
+ if status[0] != slave['file']:
+ if slave['file']:
+ self.finish_file(slave['file'])
+ slave['file'] = status[0]
+ self.start_file(slave['file'])
+ self.set_fname(slave['file'])
+ break
+ # Just working
+ self.set_status(status[1]) # Current action
+ self.set_progress(status[2] / 100.0)
+ self.window.show_all()
+ return True
+ else:
+ return True
+
+
+ #wrap up
+ # def exec_thread():
+ # print "Bar"
+ # bar = self.wTree.get_widget("Progress")
+ # flabel = self.wTree.get_widget("CurrentFilename")
+ # while self.list:
+ # et = 0
+ # active = self.list.pop(0)
+ # print active
+ # self.start_file(active)
+ # flabel.set_label(active)
+ # trk = track.Track(active, self.opts, cooked)
+ # if self.pool.add_track(trk):
+ # tsk = trk.getfirst()
+ # while tsk:
+ # self.set_status(tsk.name)
+ # tsk.run()
+ # while tsk.status() == task.RUNNING:
+ # pcent = tsk.output()
+ # try:
+ # pcent = float(pcent) / 100.0
+ # except:
+ # pcent = 0.0
+ # bar.set_fraction(pcent)
+ # et += tsk.elapsed_time()
+ # tsk.wait()
+ # tsk = tsk.next()
+ # self.finish_file(active, format_time(et))
+ # else:
+ # self.set_status("Out of space")
+ # return
+ # self.set_status("Done")
+ # flabel.set_label("")
+
+ # self.machine = threading.Thread(None, exec_thread)
+ # self.machine.start()
+
+ def set_status(self, msg):
+ """Put text in the status label"""
+ self.status = msg
+ bar = self.wTree.get_widget("StatusText")
+ bar.set_label(msg)
+ bar.show()
+
+ def set_fname(self, name):
+ """Set the current filename label"""
+ flabel = self.wTree.get_widget("CurrentFile")
+ #if len(name) > 60:
+ # self.tips.set_tip(flabel, name)
+ # name = name[-60:]
+ flabel.set_label(name)
+ flabel.show()
+
+ def set_progress(self, percent):
+ """Update the progress bar"""
+ bar = self.wTree.get_widget("Progress")
+ bar.set_fraction(percent)
+ bar.show()
+
+ def configure(self):
+ """Callback to display configure window"""
+ child = Configure(self.opts)
+ result = child.run()
+ print result
+
+ def exit(self, obj):
+ """Exit, but don't leave a mess."""
+ gtk.main_quit()
+
+
+def start_gui(opts):
+ """Run the mp3togo PyGTK interface"""
+ gobject.threads_init()
+ gui = MainWind(opts)
+ gobject.idle_add(gui.refresh_callback)
+ gtk.main()
+
--- a/mp3togo/main.py
+++ b/mp3togo/main.py
@@ -33,6 +33,7 @@ import termios
import fcntl
import mp3togo
+import mp3togo.util as util
import mp3togo.filelist as filelist
import mp3togo.conf as conf
import mp3togo.track as track
@@ -41,6 +42,8 @@ import mp3togo.pool as pool
import mp3togo.cache as cache
import mp3togo.cluster as cluster
+import mp3togo.gui.mainwindow as mainwindow
+
def fail(mesg='', code=1):
if mesg:
@@ -56,6 +59,11 @@ def main(argv):
print conf.Options().usage()
fail(str(msg))
+ # Hand off control for gui interface
+ if opts['gui']:
+ gui = mainwindow.start_gui(opts)
+ return
+
# Cluster mode is handled in the cluster module
if opts['clusterslave']:
cluster.slave(opts)
@@ -207,7 +215,7 @@ def execute_sequential(playlist, opts, c
break
except IOError: pass
tm = tsk.elapsed_time()
- ts = format_time(tm)
+ ts = util.format_time(tm)
tsk.wait()
tryp("\r ")
if tsk.status() == task.DONE:
@@ -244,14 +252,14 @@ def execute_sequential(playlist, opts, c
del trk
tt = time.time() - track_start
- ts = format_time(tt)
+ ts = util.format_time(tt)
if ts:
tryp("Total time this track: %s\n\n" % ts)
else:
tryp('\n')
tm = time.time() - start_time
- ts = format_time(tm)
+ ts = util.format_time(tm)
if bad_ones:
if bad_ones == 1:
bad_str = ", 1 track failed."
@@ -269,32 +277,5 @@ def execute_sequential(playlist, opts, c
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
-def format_time(tm):
- tm = int(tm)
- if tm:
- hr, min, sec = (tm/3600, (tm%3600)/60, (tm%3600)%60)
- ts = "%ds " % sec
- if min > 0:
- ts = ("%dm " % min) + ts
- if hr > 0:
- ts = ("%dh " % hr) + ts
- return ts[:-1]
- else:
- return ''
-
-def format_bytes(bytes):
- k = 1024.0
- m = 1024 * k
- g = 1024 * m
- if 0 < bytes < k:
- ret = str(int(bytes/k)) + " KB"
- elif k <= bytes < m:
- ret = str(int(bytes/k)) + " KB"
- elif m <= bytes < g:
- ret = str(int(bytes/m)) + " MB"
- else:
- ret = str(bytes) + " Bytes"
-
-
if __name__ == "__main__": main(sys.argv)
--- /dev/null
+++ b/mp3togo/util.py
@@ -0,0 +1,56 @@
+# - util.py -
+# General utility functions
+# This file is part of mp3togo
+#
+# (c) Simeon Veldstra 2006 <reallifesim@gmail.com>
+#
+# This software is free.
+#
+# 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 may redistribute this program under the terms of the
+# GNU General Public Licence version 2
+# Available in this package or at http://www.fsf.org
+
+"""Utility functions for mp3togo"""
+
+import sys, os
+
+
+
+
+def format_time(tm):
+ """Convert a time from floating point seconds to H:M:S"""
+ tm = int(tm)
+ if tm:
+ hr, min, sec = (tm/3600, (tm%3600)/60, (tm%3600)%60)
+ ts = "%ds " % sec
+ if min > 0:
+ ts = ("%dm " % min) + ts
+ if hr > 0:
+ if min == 0:
+ ts = "0m " + ts
+ ts = ("%dh " % hr) + ts
+ return ts[:-1]
+ else:
+ return ''
+
+def format_bytes(bytes):
+ """Express a size in human readable format"""
+ k = 1024.0
+ m = 1024 * k
+ g = 1024 * m
+ if 0 < bytes < k:
+ ret = str(int(bytes/k)) + " KB"
+ elif k <= bytes < m:
+ ret = str(int(bytes/m)) + " MB"
+ elif m <= bytes < g:
+ ret = str(int(bytes/g)) + " GB"
+ else:
+ ret = str(bytes) + " Bytes"
+ return ret
+
+
--- a/setup.py
+++ b/setup.py
@@ -72,9 +72,10 @@ use its components in another program.
The package installs a command line executable named mp3togo
in /usr/bin, for command line options, run `mp3togo --help`.""",
- packages = ["mp3togo"],
+ packages = ["mp3togo", "mp3togo.gui"],
#data_files = [('/usr/bin', ['bin/mp3togo'])],
scripts = ['bin/mp3togo'],
+ data_files = [('lib/mp3togo', ['lib/mp3togo.glade'])]
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Console',