[pitivi] projectsettings: Use ComboBox instead of TreeView for presets



commit a04700ee2b23717e93dd42176927fea8131e8dec
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Tue May 12 17:34:08 2015 +0200

    projectsettings: Use ComboBox instead of TreeView for presets
    
    This uses a bit more vertical space but saves a lot of horizontal space
    and makes the UI less cluttered.
    
    Differential Revision: https://phabricator.freedesktop.org/D356
    Reviewed-by: Thibault Saunier <tsaunier gnome org>

 data/ui/projectsettings.ui |  505 +++++++++++++++++++-------------------------
 pitivi/mainwindow.py       |    6 +-
 pitivi/preset.py           |   34 ++--
 pitivi/project.py          |  279 ++++++++++++-------------
 pitivi/render.py           |    8 +-
 5 files changed, 370 insertions(+), 462 deletions(-)
---
diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui
index 1bea536..5d1a2ac 100644
--- a/data/ui/projectsettings.ui
+++ b/data/ui/projectsettings.ui
@@ -45,17 +45,6 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="model3">
-    <columns>
-      <!-- column-name gchararray -->
-      <column type="gchararray"/>
-    </columns>
-    <data>
-      <row>
-        <col id="0" translatable="yes">25 FPS</col>
-      </row>
-    </data>
-  </object>
   <object class="GtkDialog" id="project-settings-dialog">
     <property name="can_focus">False</property>
     <property name="border_width">5</property>
@@ -129,8 +118,126 @@
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="border_width">12</property>
+                        <property name="orientation">vertical</property>
                         <property name="spacing">12</property>
                         <child>
+                          <object class="GtkBox" id="video_preset">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">end</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkLabel" id="label11">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">Preset:</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkComboBox" id="video_presets_combo">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="has_entry">True</property>
+                                <child internal-child="entry">
+                                  <object class="GtkEntry" id="combobox-entry">
+                                    <property name="can_focus">True</property>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkMenuButton" id="video_preset_menubutton">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="relief">none</property>
+                                <child>
+                                  <object class="GtkImage" id="image1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="icon_name">open-menu-symbolic</property>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkInfoBar" id="video-preset-infobar">
+                            <property name="app_paintable">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="message_type">error</property>
+                            <child internal-child="action_area">
+                              <object class="GtkButtonBox" id="infobar-action_area2">
+                                <property name="can_focus">False</property>
+                                <property name="orientation">vertical</property>
+                                <property name="layout_style">center</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child internal-child="content_area">
+                              <object class="GtkBox" id="infobar-content_area2">
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="video-preset-error-label">
+                                    <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">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
                           <object class="GtkBox" id="video_details">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
@@ -229,6 +336,7 @@
                                     <property name="can_focus">True</property>
                                     <property name="receives_default">False</property>
                                     <property name="halign">start</property>
+                                    <property name="xalign">0.5</property>
                                     <property name="draw_indicator">True</property>
                                     <signal name="toggled" handler="_constrainSarButtonToggledCb" 
swapped="no"/>
                                   </object>
@@ -282,6 +390,7 @@
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
                                         <property name="halign">start</property>
+                                        <property name="xalign">0.5</property>
                                         <property name="active">True</property>
                                         <property name="draw_indicator">True</property>
                                         <signal name="toggled" handler="_selectDarRadiobuttonToggledCb" 
swapped="no"/>
@@ -332,6 +441,7 @@
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
                                         <property name="halign">start</property>
+                                        <property name="xalign">0.5</property>
                                         <property name="draw_indicator">True</property>
                                         <property name="group">select_dar_radiobutton</property>
                                       </object>
@@ -381,7 +491,6 @@
                                   <object class="GtkComboBox" id="frame_rate_combo">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="model">model3</property>
                                     <child>
                                       <object class="GtkCellRendererText" id="renderer3"/>
                                       <attributes>
@@ -409,20 +518,55 @@
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">0</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Video</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkBox" id="audio_tab">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="border_width">12</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">12</property>
                         <child>
-                          <object class="GtkBox" id="video_preset">
+                          <object class="GtkBox" id="audio_preset">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="orientation">vertical</property>
+                            <property name="halign">start</property>
+                            <property name="spacing">6</property>
                             <child>
-                              <object class="GtkLabel" id="label11">
+                              <object class="GtkLabel" id="label10">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
                                 <property name="halign">start</property>
-                                <property name="label" translatable="yes">Video Preset</property>
+                                <property name="label" translatable="yes">Preset:</property>
                                 <attributes>
                                   <attribute name="weight" value="bold"/>
                                 </attributes>
@@ -434,45 +578,14 @@
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkInfoBar" id="video-preset-infobar">
-                                <property name="app_paintable">True</property>
+                              <object class="GtkComboBox" id="audio_presets_combo">
+                                <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="message_type">error</property>
-                                <child internal-child="action_area">
-                                  <object class="GtkButtonBox" id="infobar-action_area2">
-                                    <property name="can_focus">False</property>
-                                    <property name="orientation">vertical</property>
-                                    <property name="layout_style">center</property>
-                                    <child>
-                                      <placeholder/>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child internal-child="content_area">
-                                  <object class="GtkBox" id="infobar-content_area2">
-                                    <property name="can_focus">False</property>
-                                    <child>
-                                      <object class="GtkLabel" id="video-preset-error-label">
-                                        <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">0</property>
-                                      </packing>
-                                    </child>
+                                <property name="has_entry">True</property>
+                                <child internal-child="entry">
+                                  <object class="GtkEntry" id="combobox-entry1">
+                                    <property name="can_focus">True</property>
                                   </object>
-                                  <packing>
-                                    <property name="expand">True</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">0</property>
-                                  </packing>
                                 </child>
                               </object>
                               <packing>
@@ -482,122 +595,81 @@
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkScrolledWindow" id="scrolledwindow2">
+                              <object class="GtkMenuButton" id="audio_preset_menubutton">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
-                                <property name="hscrollbar_policy">never</property>
-                                <property name="shadow_type">in</property>
+                                <property name="receives_default">True</property>
+                                <property name="relief">none</property>
                                 <child>
-                                  <object class="GtkTreeView" id="video_preset_treeview">
+                                  <object class="GtkImage" id="image2">
                                     <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <child internal-child="selection">
-                                      <object class="GtkTreeSelection" id="treeview-selection1"/>
-                                    </child>
+                                    <property name="can_focus">False</property>
+                                    <property name="icon_name">open-menu-symbolic</property>
                                   </object>
                                 </child>
                               </object>
                               <packing>
-                                <property name="expand">True</property>
+                                <property name="expand">False</property>
                                 <property name="fill">True</property>
                                 <property name="position">2</property>
                               </packing>
                             </child>
-                            <child>
-                              <object class="GtkToolbar" id="video_presets_toolbar">
-                                <property name="visible">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkInfoBar" id="audio-preset-infobar">
+                            <property name="app_paintable">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="message_type">error</property>
+                            <child internal-child="action_area">
+                              <object class="GtkButtonBox" id="infobar-action_area3">
                                 <property name="can_focus">False</property>
-                                <property name="show_arrow">False</property>
-                                <property name="icon_size">1</property>
-                                <child>
-                                  <object class="GtkToolButton" id="add_video_preset_button">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="tooltip_text" translatable="yes">Create a new 
preset</property>
-                                    <property name="icon_name">list-add-symbolic</property>
-                                    <signal name="clicked" handler="_addVideoPresetButtonClickedCb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
-                                  </packing>
-                                </child>
+                                <property name="orientation">vertical</property>
+                                <property name="layout_style">center</property>
                                 <child>
-                                  <object class="GtkToolButton" id="remove_video_preset_button">
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Remove the selected 
preset</property>
-                                    <property name="icon_name">list-remove-symbolic</property>
-                                    <signal name="clicked" handler="_removeVideoPresetButtonClickedCb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
-                                  </packing>
+                                  <placeholder/>
                                 </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child internal-child="content_area">
+                              <object class="GtkBox" id="infobar-content_area3">
+                                <property name="can_focus">False</property>
                                 <child>
-                                  <object class="GtkToolButton" id="save_video_preset_button">
+                                  <object class="GtkLabel" id="audio-preset-error-label">
                                     <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Save changes to the 
currently selected preset</property>
-                                    <property name="icon_name">document-save-symbolic</property>
-                                    <signal name="clicked" handler="_saveVideoPresetButtonClickedCb" 
swapped="no"/>
+                                    <property name="can_focus">False</property>
+                                    <property name="opacity">0.99000000022351742</property>
                                   </object>
                                   <packing>
                                     <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
                                   </packing>
                                 </child>
                               </object>
                               <packing>
-                                <property name="expand">False</property>
+                                <property name="expand">True</property>
                                 <property name="fill">True</property>
-                                <property name="position">3</property>
+                                <property name="position">0</property>
                               </packing>
                             </child>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
+                            <property name="expand">False</property>
                             <property name="fill">True</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label6">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Video</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFrame" id="frame2">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label_xalign">0</property>
-                <child>
-                  <object class="GtkAlignment" id="alignment2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="left_padding">12</property>
-                    <child>
-                      <object class="GtkBox" id="audio_tab">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="border_width">12</property>
-                        <property name="spacing">12</property>
                         <child>
                           <object class="GtkBox" id="box1">
                             <property name="visible">True</property>
@@ -624,7 +696,7 @@
                               <object class="GtkComboBox" id="channels_combo">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="model">model3</property>
+                                <property name="halign">start</property>
                                 <child>
                                   <object class="GtkCellRendererText" id="renderer4"/>
                                   <attributes>
@@ -658,7 +730,7 @@
                               <object class="GtkComboBox" id="sample_rate_combo">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="model">model3</property>
+                                <property name="halign">start</property>
                                 <child>
                                   <object class="GtkCellRendererText" id="renderer5"/>
                                   <attributes>
@@ -676,160 +748,7 @@
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkBox" id="audio_preset">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="orientation">vertical</property>
-                            <child>
-                              <object class="GtkLabel" id="label10">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="halign">start</property>
-                                <property name="label" translatable="yes">Audio Preset</property>
-                                <attributes>
-                                  <attribute name="weight" value="bold"/>
-                                </attributes>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkInfoBar" id="audio-preset-infobar">
-                                <property name="app_paintable">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="message_type">error</property>
-                                <child internal-child="action_area">
-                                  <object class="GtkButtonBox" id="infobar-action_area3">
-                                    <property name="can_focus">False</property>
-                                    <property name="orientation">vertical</property>
-                                    <property name="layout_style">center</property>
-                                    <child>
-                                      <placeholder/>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child internal-child="content_area">
-                                  <object class="GtkBox" id="infobar-content_area3">
-                                    <property name="can_focus">False</property>
-                                    <child>
-                                      <object class="GtkLabel" id="audio-preset-error-label">
-                                        <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">0</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">True</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">True</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkScrolledWindow" id="scrolledwindow1">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="shadow_type">in</property>
-                                <child>
-                                  <object class="GtkTreeView" id="audio_preset_treeview">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <child internal-child="selection">
-                                      <object class="GtkTreeSelection" id="treeview-selection2"/>
-                                    </child>
-                                  </object>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkToolbar" id="audio_presets_toolbar">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_size">1</property>
-                                <child>
-                                  <object class="GtkToolButton" id="add_audio_preset_button">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Create a new 
preset</property>
-                                    <property name="icon_name">list-add-symbolic</property>
-                                    <signal name="clicked" handler="_addAudioPresetButtonClickedCb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkToolButton" id="remove_audio_preset_button">
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Remove the selected 
preset</property>
-                                    <property name="icon_name">list-remove-symbolic</property>
-                                    <signal name="clicked" handler="_removeAudioPresetButtonClickedCb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkToolButton" id="save_audio_preset_button">
-                                    <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Save changes to the 
currently selected preset</property>
-                                    <property name="icon_name">document-save-symbolic</property>
-                                    <signal name="clicked" handler="_saveAudioPresetButtonClickedCb" 
swapped="no"/>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="homogeneous">True</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">3</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                       </object>
diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py
index bbf2aed..fb4b27f 100644
--- a/pitivi/mainwindow.py
+++ b/pitivi/mainwindow.py
@@ -162,11 +162,11 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
         pm.connect("missing-uri", self._projectManagerMissingUriCb)
 
     def setupCss(self):
-        self.css_provider = Gtk.CssProvider()
-        self.css_provider.load_from_data(TIMELINE_CSS.encode('UTF-8'))
+        css_provider = Gtk.CssProvider()
+        css_provider.load_from_data(TIMELINE_CSS.encode('UTF-8'))
         screen = Gdk.Screen.get_default()
         style_context = self.get_style_context()
-        style_context.add_provider_for_screen(screen, self.css_provider,
+        style_context.add_provider_for_screen(screen, css_provider,
                                               Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
 
     @staticmethod
diff --git a/pitivi/preset.py b/pitivi/preset.py
index 306bd43..ce5d048 100644
--- a/pitivi/preset.py
+++ b/pitivi/preset.py
@@ -19,21 +19,25 @@
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
+import json
 import os.path
 
 from gi.repository import Gst
 from gi.repository import Gtk
-import json
 
 from gettext import gettext as _
 
-from pitivi.render import CachedEncoderList
 from pitivi.settings import xdg_data_home
 from pitivi.utils.misc import isWritable
 from pitivi.configure import get_renderpresets_dir, get_audiopresets_dir, get_videopresets_dir
 from pitivi.utils import system
 
 
+# Presets created with this name by the app should have "volatile": True
+# so they cannot be saved.
+CUSTOM_PRESET_NAME = _("Custom")
+
+
 class DuplicatePresetNameException(Exception):
 
     """Raised when an operation would result in a duplicated preset name."""
@@ -93,8 +97,7 @@ class PresetManager(object):
             self.savePreset(preset_name)
 
     def savePreset(self, preset_name):
-        if preset_name == _("No preset"):
-            return
+        assert preset_name != CUSTOM_PRESET_NAME
         if os.path.isfile(self.user_path):
             # We used to save presets as a single file instead of a directory
             os.remove(self.user_path)
@@ -206,18 +209,14 @@ class PresetManager(object):
             values = self.presets[preset]
             self.cur_preset = preset
             for field, (setter, getter) in self.widget_map.items():
-                if values[field] != 0:
-                    setter(values[field])
-                else:
-                    setter(self.presets[_("No preset")][field])
+                setter(values[field])
         finally:
             self.ignore_update_requests = False
 
     def saveCurrentPreset(self):
         """Update the current preset values from the widgets and save it."""
-        if self.cur_preset != _("No preset"):
-            self._updatePreset()
-            self.savePreset(self.cur_preset)
+        self._updatePreset()
+        self.savePreset(self.cur_preset)
 
     def _updatePreset(self):
         """Copy the values from the widgets to the preset."""
@@ -234,7 +233,9 @@ class PresetManager(object):
         return any((values[field] != getter()
                     for field, (setter, getter) in self.widget_map.items()))
 
-    def removePreset(self, name):
+    def removePreset(self, name=None):
+        if name is None:
+            name = self.cur_preset
         try:
             # Deletes json file if exists
             os.remove(self.presets[name]["filepath"])
@@ -258,14 +259,16 @@ class PresetManager(object):
 
     def isSaveButtonSensitive(self):
         """Check if the Save button should be sensitive"""
-        if not self.cur_preset or self.cur_preset == _("No preset"):
+        if not self.cur_preset:
+            return False
+        if "volatile" in self.presets[self.cur_preset]:
             return False
         try:
             full_path = self.presets[self.cur_preset]["filepath"]
-            (dir, name) = os.path.split(full_path)
         except KeyError:
             # This is a newly created preset that has not yet been saved
             return True
+        (dir, name) = os.path.split(full_path)
         if dir == self.default_path or not isWritable(full_path):
             # default_path is the system-wide directory where the default
             # presets are installed; they are not expected to be editable.
@@ -275,7 +278,7 @@ class PresetManager(object):
 
     def isRemoveButtonSensitive(self):
         """Check if Remove buttons should be sensitive"""
-        if not self.cur_preset or self.cur_preset == _("No preset"):
+        if not self.cur_preset:
             return False
         try:
             full_path = self.presets[self.cur_preset]["filepath"]
@@ -387,6 +390,7 @@ class RenderPresetManager(PresetManager):
         acodec = parser["acodec"]
         vcodec = parser["vcodec"]
 
+        from pitivi.render import CachedEncoderList
         cached_encs = CachedEncoderList()
         if (acodec not in [fact.get_name() for fact in cached_encs.aencoders] or
                 vcodec not in [fact.get_name() for fact in cached_encs.vencoders] or
diff --git a/pitivi/project.py b/pitivi/project.py
index 378a69d..a216d5c 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -27,6 +27,7 @@ Project related classes
 import os
 from gi.repository import GstPbutils
 from gi.repository import GES
+from gi.repository import Gio
 from gi.repository import Gst
 from gi.repository import Gtk
 from gi.repository import GLib
@@ -38,9 +39,8 @@ from datetime import datetime
 from gettext import gettext as _
 from pwd import getpwuid
 
-from pitivi.undo.undo import UndoableAction
 from pitivi.configure import get_ui_dir
-
+from pitivi.undo.undo import UndoableAction
 from pitivi.utils.validate import has_validate, create_monitor
 from pitivi.utils.misc import quote_uri, path_from_uri, isWritable, unicode_error_dialog
 from pitivi.utils.pipeline import PipelineError, Seeker
@@ -1367,12 +1367,13 @@ class ProjectSettingsDialog():
 
     def __init__(self, parent_window, project):
         self.project = project
+        self.audio_presets = AudioPresetManager()
+        self.video_presets = VideoPresetManager()
+        self.preset_actions = {}
         self._createUi()
         self.window.set_transient_for(parent_window)
         self._setupUiConstraints()
         self.updateUI()
-        self.createAudioNoPreset(self.audio_presets)
-        self.createVideoNoPreset(self.video_presets)
 
     def _createUi(self):
         """
@@ -1394,13 +1395,9 @@ class ProjectSettingsDialog():
         self.author_entry = getObj("author_entry")
         self.width_spinbutton = getObj("width_spinbutton")
         self.height_spinbutton = getObj("height_spinbutton")
-        self.save_audio_preset_button = getObj("save_audio_preset_button")
-        self.save_video_preset_button = getObj("save_video_preset_button")
-        self.audio_preset_treeview = getObj("audio_preset_treeview")
-        self.video_preset_treeview = getObj("video_preset_treeview")
+        self.audio_presets_combo = getObj("audio_presets_combo")
+        self.video_presets_combo = getObj("video_presets_combo")
         self.select_par_radiobutton = getObj("select_par_radiobutton")
-        self.remove_audio_preset_button = getObj("remove_audio_preset_button")
-        self.remove_video_preset_button = getObj("remove_video_preset_button")
         self.constrain_sar_button = getObj("constrain_sar_button")
         self.select_dar_radiobutton = getObj("select_dar_radiobutton")
         self.video_preset_infobar = getObj("video-preset-infobar")
@@ -1409,13 +1406,16 @@ class ProjectSettingsDialog():
         self.author_entry = getObj("author_entry")
         self.year_spinbutton = getObj("year_spinbutton")
 
-        # Set the shading style in the contextual toolbars below presets
-        video_presets_toolbar = getObj("video_presets_toolbar")
-        audio_presets_toolbar = getObj("audio_presets_toolbar")
-        video_presets_toolbar.get_style_context().add_class(
-            Gtk.STYLE_CLASS_INLINE_TOOLBAR)
-        audio_presets_toolbar.get_style_context().add_class(
-            Gtk.STYLE_CLASS_INLINE_TOOLBAR)
+        self.video_preset_menubutton = getObj("video_preset_menubutton")
+        self._createPresetMenu(self.video_preset_menubutton,
+                               self._addVideoPresetCb,
+                               self.video_presets,
+                               self.video_presets_combo)
+        self.audio_preset_menubutton = getObj("audio_preset_menubutton")
+        self._createPresetMenu(self.audio_preset_menubutton,
+                               self._addAudioPresetCb,
+                               self.audio_presets,
+                               self.audio_presets_combo)
 
     def _setupUiConstraints(self):
         """
@@ -1461,10 +1461,10 @@ class ProjectSettingsDialog():
         self.wg.addVertex(self.par_fraction_widget, signal="value-changed")
         self.wg.addVertex(self.width_spinbutton, signal="value-changed")
         self.wg.addVertex(self.height_spinbutton, signal="value-changed")
-        self.wg.addVertex(self.save_audio_preset_button,
-                          update_func=self._updateAudioSaveButton)
-        self.wg.addVertex(self.save_video_preset_button,
-                          update_func=self._updateVideoSaveButton)
+        self.wg.addVertex(self.audio_preset_menubutton,
+                          update_func=self._updateAudioPresetMenuButton)
+        self.wg.addVertex(self.video_preset_menubutton,
+                          update_func=self._updateVideoPresetMenuButton)
         self.wg.addVertex(self.channels_combo, signal="changed")
         self.wg.addVertex(self.sample_rate_combo, signal="changed")
 
@@ -1516,16 +1516,12 @@ class ProjectSettingsDialog():
                         edge_func=self.updateDarFromPar)
 
         # Presets.
-        self.audio_presets = AudioPresetManager()
-        self.audio_presets.loadAll()
-        self._fillPresetsTreeview(self.audio_preset_treeview,
-                                  self.audio_presets,
-                                  self._updateAudioPresetButtons)
-        self.video_presets = VideoPresetManager()
-        self.video_presets.loadAll()
-        self._fillPresetsTreeview(self.video_preset_treeview,
-                                  self.video_presets,
-                                  self._updateVideoPresetButtons)
+        self._loadPresets(self.audio_presets,
+                          self.audio_presets_combo,
+                          self.audio_preset_menubutton)
+        self._loadPresets(self.video_presets,
+                          self.video_presets_combo,
+                          self.video_preset_menubutton)
 
         # A map which tells which infobar should be used when displaying
         # an error for a preset manager.
@@ -1547,14 +1543,14 @@ class ProjectSettingsDialog():
             self.audio_presets, "sample-rate", self.sample_rate_combo)
 
         self.wg.addEdge(
-            self.par_fraction_widget, self.save_video_preset_button)
+            self.par_fraction_widget, self.video_preset_menubutton)
         self.wg.addEdge(
-            self.frame_rate_fraction_widget, self.save_video_preset_button)
-        self.wg.addEdge(self.width_spinbutton, self.save_video_preset_button)
-        self.wg.addEdge(self.height_spinbutton, self.save_video_preset_button)
+            self.frame_rate_fraction_widget, self.video_preset_menubutton)
+        self.wg.addEdge(self.width_spinbutton, self.video_preset_menubutton)
+        self.wg.addEdge(self.height_spinbutton, self.video_preset_menubutton)
 
-        self.wg.addEdge(self.channels_combo, self.save_audio_preset_button)
-        self.wg.addEdge(self.sample_rate_combo, self.save_audio_preset_button)
+        self.wg.addEdge(self.channels_combo, self.audio_preset_menubutton)
+        self.wg.addEdge(self.sample_rate_combo, self.audio_preset_menubutton)
 
     def bindPar(self, mgr):
 
@@ -1579,76 +1575,80 @@ class ProjectSettingsDialog():
                        lambda x: widget.set_value(float(x)),
                        lambda: int(widget.get_value()))
 
-    def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func):
+    def _createPresetMenu(self, button, new_func, mgr, combo):
+        entry = combo.get_child()
+        style_context = entry.get_style_context()
+        style_provider = Gtk.CssProvider()
+        style_provider.load_from_data("GtkEntry.unsaved {font-style:italic;}".encode('UTF-8'))
+        style_context.add_provider(style_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
+
+        action_group = Gio.SimpleActionGroup()
+        menu_model = Gio.Menu()
+        self.preset_actions[button] = {}
+
+        action = Gio.SimpleAction.new("new", None)
+        action.connect("activate", new_func)
+        action_group.insert(action)
+        menu_model.append(_("New"), "preset.%s" % action.get_name())
+        self.preset_actions[button][action.get_name()] = action
+
+        action = Gio.SimpleAction.new("remove", None)
+        action.connect("activate", self._removePresetCb, button, combo, mgr)
+        action_group.insert(action)
+        menu_model.append(_("Remove"), "preset.%s" % action.get_name())
+        self.preset_actions[button][action.get_name()] = action
+
+        action = Gio.SimpleAction.new("save", None)
+        action.connect("activate", self._savePresetCb, mgr, button, combo)
+        action_group.insert(action)
+        menu_model.append(_("Save"), "preset.%s" % action.get_name())
+        self.preset_actions[button][action.get_name()] = action
+
+        menu = Gtk.Menu.new_from_model(menu_model)
+        menu.insert_action_group("preset", action_group)
+        button.set_popup(menu)
+
+    def _updatePresetActions(self, button, combo, mgr):
+        entry = combo.get_child()
+        preset_name = entry.get_text()
+        can_save = mgr.cur_preset != preset_name or mgr.isSaveButtonSensitive()
+        self.preset_actions[button]["save"].set_enabled(can_save)
+        if can_save:
+            entry.get_style_context().add_class("unsaved")
+        else:
+            entry.get_style_context().remove_class("unsaved")
+
+        can_remove = mgr.isRemoveButtonSensitive()
+        self.preset_actions[button]["remove"].set_enabled(can_remove)
+
+    def _loadPresets(self, mgr, combo, button):
         """Set up the specified treeview to display the specified presets.
 
-        @param treeview: The treeview for displaying the presets.
-        @type treeview: TreeView
         @param mgr: The preset manager.
         @type mgr: PresetManager
-        @param update_buttons_func: A function which updates the buttons for
-        removing and saving a preset, enabling or disabling them accordingly.
-        @type update_buttons_func: function
+        @param combo: The combobox displaying the presets.
+        @type combo: Gtk.ComboBox
+        @param button: The menubutton associated with the combobox.
+        @type button: Gtk.MenuButton
         """
-        renderer = Gtk.CellRendererText()
-        renderer.props.editable = True
-        column = Gtk.TreeViewColumn("Preset", renderer, text=0)
-        treeview.append_column(column)
-        treeview.props.headers_visible = False
+        mgr.loadAll()
         model = mgr.getModel()
-        treeview.set_model(model)
-        model.connect(
-            "row-inserted", self._newPresetCb, column, renderer, treeview)
-        renderer.connect("edited", self._presetNameEditedCb, mgr)
-        renderer.connect(
-            "editing-started", self._presetNameEditingStartedCb, mgr)
-        treeview.get_selection().connect("changed", self._presetChangedCb, mgr,
-                                         update_buttons_func)
-        treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr)
-
-    def createAudioNoPreset(self, mgr):
-        mgr.prependPreset(_("No preset"), {
-            "channels": self.project.audiochannels,
-            "sample-rate": self.project.audiorate})
-
-    def createVideoNoPreset(self, mgr):
-        mgr.prependPreset(_("No preset"), {
-            "par": self.project.videopar,
-            "frame-rate": self.project.videorate,
-            "height": self.project.videoheight,
-            "width": self.project.videowidth})
-
-    def _newPresetCb(self, unused_model, path, unused_iter_, column, renderer, treeview):
-        """ Handle the addition of a preset to the model of the preset manager. """
-        treeview.set_cursor_on_cell(path, column, renderer, start_editing=True)
-        treeview.grab_focus()
-
-    def _presetNameEditedCb(self, unused_renderer, path, new_text, mgr):
-        """Handle the renaming of a preset."""
-        try:
-            mgr.renamePreset(path, new_text)
-        except DuplicatePresetNameException:
-            error_markup = _('"%s" already exists.') % new_text
-            self._showPresetManagerError(mgr, error_markup)
+        combo.set_model(model)
+        combo.set_entry_text_column(0)
+        combo.connect("changed", self._presetChangedCb, mgr, button)
 
-    def _presetNameEditingStartedCb(self, unused_renderer, unused_editable, unused_path, mgr):
-        """Handle the start of a preset renaming."""
-        self._hidePresetManagerError(mgr)
-
-    def _presetChangedCb(self, selection, mgr, update_preset_buttons_func):
+    def _presetChangedCb(self, combo, mgr, button):
         """Handle the selection of a preset."""
-        model, iter_ = selection.get_selected()
-        if iter_:
-            preset = model[iter_][0]
+        preset_name = combo.get_active_id()
+        if preset_name:
+            # The user selected a preset.
+            mgr.restorePreset(preset_name)
+            self._updateSar()
+            self._updatePresetActions(button, combo, mgr)
+            self._hidePresetManagerError(mgr)
         else:
-            preset = None
-        mgr.restorePreset(preset)
-        self._updateSar()
-        update_preset_buttons_func()
-        self._hidePresetManagerError(mgr)
-
-    def _treeviewDefocusedCb(self, unused_widget, unused_event, mgr):
-        self._hidePresetManagerError(mgr)
+            # The user is editing the preset name.
+            self._updatePresetActions(button, combo, mgr)
 
     def _showPresetManagerError(self, mgr, error_markup):
         """Show the specified error on the infobar associated with the manager.
@@ -1711,27 +1711,16 @@ class ProjectSettingsDialog():
             i += 1
         return preset_name
 
-    def _addAudioPresetButtonClickedCb(self, unused_button):
+    def _addAudioPresetCb(self, unused_action, unused_param):
         preset_name = self._getUniquePresetName(self.audio_presets)
         self.audio_presets.addPreset(preset_name, {
             "channels": get_combo_value(self.channels_combo),
             "sample-rate": get_combo_value(self.sample_rate_combo),
         })
-        self.audio_presets.restorePreset(preset_name)
-        self._updateAudioPresetButtons()
+        self.audio_presets_combo.set_active_id(preset_name)
+        self._updateAudioPresetMenu()
 
-    def _removeAudioPresetButtonClickedCb(self, unused_button):
-        selection = self.audio_preset_treeview.get_selection()
-        model, iter_ = selection.get_selected()
-        if iter_:
-            self.audio_presets.removePreset(model[iter_][0])
-
-    def _saveAudioPresetButtonClickedCb(self, unused_button):
-        self.audio_presets.saveCurrentPreset()
-        self.save_audio_preset_button.set_sensitive(False)
-        self.remove_audio_preset_button.set_sensitive(True)
-
-    def _addVideoPresetButtonClickedCb(self, unused_button):
+    def _addVideoPresetCb(self, unused_action, unused_param):
         preset_name = self._getUniquePresetName(self.video_presets)
         self.video_presets.addPreset(preset_name, {
             "width": int(self.width_spinbutton.get_value()),
@@ -1739,37 +1728,32 @@ class ProjectSettingsDialog():
             "frame-rate": self.frame_rate_fraction_widget.getWidgetValue(),
             "par": self.par_fraction_widget.getWidgetValue(),
         })
-        self.video_presets.restorePreset(preset_name)
-        self._updateVideoPresetButtons()
-
-    def _removeVideoPresetButtonClickedCb(self, unused_button):
-        selection = self.video_preset_treeview.get_selection()
-        model, iter_ = selection.get_selected()
-        if iter_:
-            self.video_presets.removePreset(model[iter_][0])
-
-    def _saveVideoPresetButtonClickedCb(self, unused_button):
-        self.video_presets.saveCurrentPreset()
-        self.save_video_preset_button.set_sensitive(False)
-        self.remove_video_preset_button.set_sensitive(True)
-
-    def _updateAudioPresetButtons(self):
-        can_save = self.audio_presets.isSaveButtonSensitive()
-        self.save_audio_preset_button.set_sensitive(can_save)
-        can_remove = self.audio_presets.isRemoveButtonSensitive()
-        self.remove_audio_preset_button.set_sensitive(can_remove)
-
-    def _updateVideoPresetButtons(self):
-        self.save_video_preset_button.set_sensitive(
-            self.video_presets.isSaveButtonSensitive())
-        self.remove_video_preset_button.set_sensitive(
-            self.video_presets.isRemoveButtonSensitive())
-
-    def _updateAudioSaveButton(self, unused_in, button):
-        button.set_sensitive(self.audio_presets.isSaveButtonSensitive())
-
-    def _updateVideoSaveButton(self, unused_in, button):
-        button.set_sensitive(self.video_presets.isSaveButtonSensitive())
+        self.video_presets_combo.set_active_id(preset_name)
+        self._updateVideoPresetMenu()
+
+    def _removePresetCb(self, unused_action, unused_param, button, combo, mgr):
+        mgr.removePreset()
+        self._updatePresetActions(button, combo, mgr)
+
+    def _savePresetCb(self, unused_action, unused_param, mgr, button, combo):
+        mgr.saveCurrentPreset()
+        self._updatePresetActions(button, combo, mgr)
+
+    def _updateAudioPresetMenuButton(self, unused_source, unused_target):
+        self._updateAudioPresetMenu()
+
+    def _updateAudioPresetMenu(self):
+        button = self.audio_preset_menubutton
+        combo = self.audio_presets_combo
+        self._updatePresetActions(button, combo, self.audio_presets)
+
+    def _updateVideoPresetMenuButton(self, unused_source, unused_target):
+        self._updateVideoPresetMenu()
+
+    def _updateVideoPresetMenu(self):
+        button = self.video_preset_menubutton
+        combo = self.video_presets_combo
+        self._updatePresetActions(button, combo, self.video_presets)
 
     def darSelected(self):
         return self.select_dar_radiobutton.props.active
@@ -1838,12 +1822,11 @@ class ProjectSettingsDialog():
             year = datetime.now().year
         self.year_spinbutton.get_adjustment().set_value(year)
 
-    def updateMetadata(self):
+    def updateProject(self):
         self.project.name = self.title_entry.get_text()
         self.project.author = self.author_entry.get_text()
         self.project.year = str(self.year_spinbutton.get_value_as_int())
 
-    def updateSettings(self):
         self.project.videowidth = int(self.width_spinbutton.get_value())
         self.project.videoheight = int(self.height_spinbutton.get_value())
         self.project.videopar = self.par_fraction_widget.getWidgetValue()
@@ -1854,7 +1837,7 @@ class ProjectSettingsDialog():
         self.project.audiorate = get_combo_value(self.sample_rate_combo)
 
     def _responseCb(self, unused_widget, response):
+        """Handle the dialog being closed."""
         if response == Gtk.ResponseType.OK:
-            self.updateSettings()
-            self.updateMetadata()
+            self.updateProject()
         self.window.destroy()
diff --git a/pitivi/render.py b/pitivi/render.py
index 7a169d5..ecc808d 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -39,6 +39,7 @@ from gettext import gettext as _
 from pitivi import configure
 
 from pitivi.check import missing_soft_deps
+from pitivi.preset import CUSTOM_PRESET_NAME
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import show_user_manual, path_from_uri
 from pitivi.utils.ripple_update_group import RippleUpdateGroup
@@ -421,10 +422,11 @@ class RenderDialog(Loggable):
         self.bindHeight(self.render_presets)
         self.bindWidth(self.render_presets)
 
-        self.createNoPreset(self.render_presets)
+        self.createVolatileCustomPreset(self.render_presets)
 
-    def createNoPreset(self, mgr):
-        mgr.prependPreset(_("No preset"), {
+    def createVolatileCustomPreset(self, mgr):
+        mgr.prependPreset(CUSTOM_PRESET_NAME, {
+            "volatile": True,
             "channels": int(get_combo_value(self.channels_combo)),
             "sample-rate": int(get_combo_value(self.sample_rate_combo)),
             "acodec": get_combo_value(self.audio_encoder_combo).get_name(),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]