[gnome-music/wip/jfelder/musicbrainz-tageditordialog: 208/209] tageditordialog: Initial songs support



commit 18a5276010ba90fd24f7086a0599f1e5290145e9
Author: Jean Felder <jfelder src gnome org>
Date:   Tue Aug 21 00:59:11 2018 +0200

    tageditordialog: Initial songs support

 data/org.gnome.Music.gresource.xml     |   1 +
 data/ui/SelectionToolbar.ui            |  12 +
 data/ui/TagEditorDialog.ui             | 847 +++++++++++++++++++++++++++++++++
 gnomemusic/utils.py                    |   2 +-
 gnomemusic/widgets/selectiontoolbar.py |  23 +-
 gnomemusic/widgets/tageditordialog.py  | 130 +++++
 gnomemusic/window.py                   |  20 +
 po/POTFILES.in                         |   2 +
 8 files changed, 1030 insertions(+), 7 deletions(-)
---
diff --git a/data/org.gnome.Music.gresource.xml b/data/org.gnome.Music.gresource.xml
index 3992ffa4..a4fc04cc 100644
--- a/data/org.gnome.Music.gresource.xml
+++ b/data/org.gnome.Music.gresource.xml
@@ -25,6 +25,7 @@
     <file preprocess="xml-stripblanks">ui/SelectionToolbar.ui</file>
     <file preprocess="xml-stripblanks">ui/SidebarRow.ui</file>
     <file preprocess="xml-stripblanks">ui/SongWidget.ui</file>
+    <file preprocess="xml-stripblanks">ui/TagEditorDialog.ui</file>
     <file preprocess="xml-stripblanks">ui/TwoLineTip.ui</file>
     <file preprocess="xml-stripblanks">ui/Window.ui</file>
   </gresource>
diff --git a/data/ui/SelectionToolbar.ui b/data/ui/SelectionToolbar.ui
index ec64876c..577f9d88 100644
--- a/data/ui/SelectionToolbar.ui
+++ b/data/ui/SelectionToolbar.ui
@@ -17,5 +17,17 @@
         </style>
       </object>
     </child>
+    <child>
+      <object class="GtkButton" id="_edit_details_button">
+        <property name="label" translatable="yes">Edit Details</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <signal name="clicked" handler="_on_edit_tags_button_clicked" swapped="no"/>
+        <style>
+          <class name="text-button"/>
+        </style>
+      </object>
+</child>
   </template>
 </interface>
diff --git a/data/ui/TagEditorDialog.ui b/data/ui/TagEditorDialog.ui
new file mode 100644
index 00000000..3608c8ca
--- /dev/null
+++ b/data/ui/TagEditorDialog.ui
@@ -0,0 +1,847 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <template class="TagEditorDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="skip_taskbar_hint">True</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog_vbox">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkOverlay" id="overlay">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkBox" id="media_details">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="margin_left">12</property>
+                <property name="margin_right">12</property>
+                <property name="margin_top">12</property>
+                <property name="margin_bottom">18</property>
+                <property name="spacing">24</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkButton" id="_coverart_button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="focus_on_click">False</property>
+                        <property name="receives_default">False</property>
+                        <property name="halign">start</property>
+                        <property name="valign">start</property>
+                        <property name="relief">none</property>
+                        <signal name="clicked" handler="_choose_cover" swapped="no"/>
+                        <child>
+                          <object class="CoverStack" id="_cover_stack">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="valign">start</property>
+                          </object>
+                        </child>
+                        <style>
+                          <class name="album-cover"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</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">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="width_request">260</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="title">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_right">36</property>
+                                <property name="label" translatable="yes">Title</property>
+                                <property name="xalign">1</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_title_suggestion">
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_right">2</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="_title_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="album">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_right">36</property>
+                                <property name="label" translatable="yes">Album</property>
+                                <property name="xalign">1</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_album_suggestion">
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_right">2</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="_album_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</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="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="artist">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_right">36</property>
+                                <property name="label" translatable="yes">Artist</property>
+                                <property name="xalign">1</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_artist_suggestion">
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_right">2</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="_artist_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="composer">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_right">36</property>
+                                <property name="label" translatable="yes">Composer</property>
+                                <property name="xalign">1</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_composer_suggestion">
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_right">2</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="_composer_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="genre">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="margin_right">36</property>
+                                <property name="label" translatable="yes">Genre</property>
+                                <property name="xalign">1</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="_genre_suggestion">
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="margin_right">2</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="_genre_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="spacing">12</property>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkBox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="track">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Song</property>
+                                    <property name="xalign">1</property>
+                                    <attributes>
+                                      <attribute name="weight" value="bold"/>
+                                    </attributes>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="_track_suggestion">
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">end</property>
+                                    <property name="margin_right">2</property>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="pack_type">end</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkEntry" id="_track_entry">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="width_chars">8</property>
+                                <property name="max_width_chars">2</property>
+                                <property name="input_purpose">number</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkBox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="disc">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">start</property>
+                                    <property name="hexpand">True</property>
+                                    <property name="label" translatable="yes">Disc</property>
+                                    <attributes>
+                                      <attribute name="weight" value="bold"/>
+                                    </attributes>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="_disc_suggestion">
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">start</property>
+                                    <property name="margin_right">2</property>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkEntry" id="_disc_entry">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="max_length">2</property>
+                                <property name="width_chars">8</property>
+                                <property name="max_width_chars">2</property>
+                                <property name="input_purpose">number</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkBox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="year">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">start</property>
+                                    <property name="hexpand">True</property>
+                                    <property name="label" translatable="yes">Year</property>
+                                    <attributes>
+                                      <attribute name="weight" value="bold"/>
+                                    </attributes>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="_year_suggestion">
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">start</property>
+                                    <property name="margin_right">2</property>
+                                    <style>
+                                      <class name="dim-label"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkEntry" id="_year_entry">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="max_length">4</property>
+                                <property name="width_chars">10</property>
+                                <property name="max_width_chars">4</property>
+                                <property name="input_purpose">number</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">5</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="index">-1</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="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="margin_right">12</property>
+            <property name="margin_bottom">12</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="valign">end</property>
+                <property name="spacing">6</property>
+                <property name="baseline_position">bottom</property>
+                <child>
+                  <object class="GtkSpinner" id="_spinner">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="active">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="_spinner_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Fetching metadata...</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="hexpand">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="halign">end</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">go-next-symbolic-rtl</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="halign">start</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">go-next-symbolic</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <style>
+                      <class name="linked"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="_use_suggestion_button">
+                    <property name="label" translatable="yes">Use Suggestions</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <style>
+                      <class name="suggested-action"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </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">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkHeaderBar" id="_title_bar">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Edit Details</property>
+    <property name="show_close_button">True</property>
+  </object>
+</interface>
diff --git a/gnomemusic/utils.py b/gnomemusic/utils.py
index 7294dfdd..8d4b874a 100644
--- a/gnomemusic/utils.py
+++ b/gnomemusic/utils.py
@@ -186,4 +186,4 @@ fields = {
     'title': get_media_title,
     'track': get_media_track_nr,
     'year': get_media_year
-    }
+}
diff --git a/gnomemusic/widgets/selectiontoolbar.py b/gnomemusic/widgets/selectiontoolbar.py
index 1d2b775a..517d0faf 100644
--- a/gnomemusic/widgets/selectiontoolbar.py
+++ b/gnomemusic/widgets/selectiontoolbar.py
@@ -33,9 +33,11 @@ class SelectionToolbar(Gtk.ActionBar):
     __gtype_name__ = 'SelectionToolbar'
 
     _add_to_playlist_button = Gtk.Template.Child()
+    _edit_details_button = Gtk.Template.Child()
 
     __gsignals__ = {
-        'add-to-playlist': (GObject.SignalFlags.RUN_FIRST, None, ())
+        'add-to-playlist': (GObject.SignalFlags.RUN_FIRST, None, ()),
+        'edit-details': (GObject.SignalFlags.RUN_FIRST, None, ())
     }
 
     selected_items_count = GObject.Property(type=int, default=0, minimum=0)
@@ -44,9 +46,10 @@ class SelectionToolbar(Gtk.ActionBar):
         return '<SelectionToolbar>'
 
     @log
-    def __init__(self):
+    def __init__(self, window):
         super().__init__()
 
+        self._headerbar = window._headerbar
         self.connect(
             'notify::selected-items-count', self._on_item_selection_changed)
 
@@ -55,9 +58,17 @@ class SelectionToolbar(Gtk.ActionBar):
     def _on_add_to_playlist_button_clicked(self, widget):
         self.emit('add-to-playlist')
 
+    @Gtk.Template.Callback()
+    @log
+    def _on_edit_tags_button_clicked(self, widget):
+        self.emit('edit-details')
+
     @log
     def _on_item_selection_changed(self, widget, data):
-        if self.props.selected_items_count > 0:
-            self._add_to_playlist_button.props.sensitive = True
-        else:
-            self._add_to_playlist_button.props.sensitive = False
+        stack = self._headerbar.props.stack
+        songs_view_visible = (stack.props.visible_child_name == 'songs')
+        selection_size = self.props.selected_items_count
+
+        self._add_to_playlist_button.props.sensitive = (selection_size > 0)
+        self._edit_details_button.props.sensitive = (selection_size == 1
+                                                     and songs_view_visible)
diff --git a/gnomemusic/widgets/tageditordialog.py b/gnomemusic/widgets/tageditordialog.py
new file mode 100644
index 00000000..123e5201
--- /dev/null
+++ b/gnomemusic/widgets/tageditordialog.py
@@ -0,0 +1,130 @@
+# Copyright 2018 The GNOME Music Developers
+#
+# GNOME Music 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.
+#
+# GNOME Music 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 GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music.  This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered.  If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so.  If you do not wish to do so,
+# delete this exception statement from your version.
+
+import logging
+from gettext import gettext as _
+
+from gi.repository import Grl, Gtk
+
+from gnomemusic import log
+from gnomemusic.albumartcache import Art
+from gnomemusic.grilo import grilo
+import gnomemusic.utils as utils
+
+logger = logging.getLogger(__name__)
+
+
+@Gtk.Template(resource_path="/org/gnome/Music/ui/TagEditorDialog.ui")
+class TagEditorDialog(Gtk.Dialog):
+    """Tag editor widget
+    A tag editor dialog box that allows storing metadata for music files
+    through editing entries manually or applying automatic fetched tags.
+    """
+
+    __gtype_name__ = 'TagEditorDialog'
+
+    _cover_stack = Gtk.Template.Child()
+    _spinner = Gtk.Template.Child()
+    _spinner_label = Gtk.Template.Child()
+    _title_bar = Gtk.Template.Child()
+
+    # tags entries and labels
+    _album_entry = Gtk.Template.Child()
+    _album_suggestion = Gtk.Template.Child()
+    _artist_entry = Gtk.Template.Child()
+    _artist_suggestion = Gtk.Template.Child()
+    _composer_entry = Gtk.Template.Child()
+    _composer_suggestion = Gtk.Template.Child()
+    _disc_entry = Gtk.Template.Child()
+    _disc_suggestion = Gtk.Template.Child()
+    _genre_entry = Gtk.Template.Child()
+    _genre_suggestion = Gtk.Template.Child()
+    _title_entry = Gtk.Template.Child()
+    _title_suggestion = Gtk.Template.Child()
+    _track_entry = Gtk.Template.Child()
+    _track_suggestion = Gtk.Template.Child()
+    _year_entry = Gtk.Template.Child()
+    _year_suggestion = Gtk.Template.Child()
+
+    def __repr__(self):
+        return '<TagEditorDialog>'
+
+    @log
+    def __init__(self, parent, selected_song):
+        """Initialize the tag editor
+        :param parent: The parent widget calling the editor dialog box
+        :param selected_song: The current selected track which is being edited
+        """
+        super().__init__()
+
+        self.props.transient_for = parent
+        self.set_titlebar(self._title_bar)
+
+        self._cover_stack.props.size = Art.Size.MEDIUM
+        self._cover_stack.update(selected_song)
+
+        self._initial_song = selected_song
+        self._init_labels()
+        self._search_tags()
+
+    @log
+    def _init_labels(self):
+        for field in utils.fields:
+            entry = getattr(self, '_' + field + '_entry')
+            value = utils.fields[field](self._initial_song)
+            if value:
+                entry.props.text = value
+
+    @log
+    def _start_spinner(self, text):
+        self._spinner.start()
+        self._spinner_label.props.label = text
+
+    @log
+    def _stop_spinner(self):
+        self._spinner.stop()
+        self._spinner_label.props.label = ""
+
+    @log
+    def _search_tags(self):
+        self._start_spinner(_("Fetching metadata…"))
+        new_media = Grl.Media.audio_new()
+        new_media.set_url(self._initial_song.get_url())
+        grilo.get_tags_from_musicbrainz(new_media, self._tags_found)
+
+    @log
+    def _tags_found(self, media):
+        if media is None:
+            logger.warning("Unable to find tags for song {}".format(
+                self._initial_song.get_url()))
+            self._stop_spinner()
+            return
+
+        for field in utils.fields:
+            suggestion = getattr(self, '_' + field + '_suggestion')
+            value = utils.fields[field](media)
+            if value:
+                suggestion.props.label = value
+                suggestion.props.visible = True
+        self._stop_spinner()
diff --git a/gnomemusic/window.py b/gnomemusic/window.py
index 7b7141dc..c1661c14 100644
--- a/gnomemusic/window.py
+++ b/gnomemusic/window.py
@@ -46,6 +46,7 @@ from gnomemusic.widgets.playertoolbar import PlayerToolbar
 from gnomemusic.widgets.playlistdialog import PlaylistDialog
 from gnomemusic.widgets.searchbar import SearchBar
 from gnomemusic.widgets.selectiontoolbar import SelectionToolbar  # noqa: F401
+from gnomemusic.widgets.tageditordialog import TagEditorDialog
 from gnomemusic.windowplacement import WindowPlacement
 
 import logging
@@ -187,6 +188,7 @@ class Window(Gtk.ApplicationWindow):
 
         self._selection_toolbar.connect(
             'add-to-playlist', self._on_add_to_playlist)
+        self._selection_toolbar.connect('edit-details', self._on_edit_tags)
         self._search.connect("notify::state", self._on_search_state_changed)
 
         self._headerbar.props.state = HeaderBar.State.MAIN
@@ -500,6 +502,24 @@ class Window(Gtk.ApplicationWindow):
 
         self._stack.get_visible_child().get_selected_songs(callback)
 
+    @log
+    def _on_edit_tags(self, widget):
+        if self._stack.get_visible_child() == self.views[View.PLAYLIST]:
+            return
+
+        def callback(selected_songs):
+            if len(selected_songs) < 1:
+                return
+
+            tags_editor_dialog = TagEditorDialog(self, selected_songs[0])
+            if tags_editor_dialog.run() == Gtk.ResponseType.ACCEPT:
+                return
+
+            self.props.selection_mode = False
+            tags_editor_dialog.destroy()
+
+        self._stack.get_visible_child().get_selected_songs(callback)
+
     @log
     def set_player_visible(self, visible):
         """Set PlayWidget action visibility
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0fea8e4b..50a46c2b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,6 +14,7 @@ data/ui/PlaylistControls.ui
 data/ui/PlaylistDialog.ui
 data/ui/SelectionBarMenuButton.ui
 data/ui/SelectionToolbar.ui
+data/ui/TagEditorDialog.ui
 gnomemusic/__init__.py
 gnomemusic/albumartcache.py
 gnomemusic/application.py
@@ -40,4 +41,5 @@ gnomemusic/widgets/playlistcontrols.py
 gnomemusic/widgets/playlistdialog.py
 gnomemusic/widgets/searchbar.py
 gnomemusic/widgets/starhandlerwidget.py
+gnomemusic/widgets/tageditordialog.py
 gnomemusic/window.py


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