Explorar o código

various fixes

Olivier Massot %!s(int64=4) %!d(string=hai) anos
pai
achega
281f727ae5

+ 15 - 0
core/file_utilities.py

@@ -1,5 +1,9 @@
 import hashlib
 import mimetypes
+import os
+import platform
+import subprocess
+import sys
 
 MEDIA_EXTS_CACHE = ['.mp3', '.wma', '.flac', '.mp4']
 
@@ -37,3 +41,14 @@ def is_subdir_of(subject, other):
     if subject.parent == other:
         return True
     return is_subdir_of(subject.parent, other)
+
+
+def open_file(path_):
+    if sys.platform == 'darwin':
+        subprocess.check_call(['open', str(path_)])
+    elif sys.platform == 'linux':
+        subprocess.check_call(['xdg-open', str(path_)])
+    elif sys.platform == 'win32':
+        subprocess.check_call(['explorer', str(path_)])
+    else:
+        raise RuntimeError(f"Unsupported platform {sys.platform}")

+ 1 - 1
core/utils.py

@@ -2,4 +2,4 @@
 
 def norm_search(s):
     return s.lower().replace("é", "e").replace("è", "e").replace("ê", "e").replace("ë", "e").replace("ç", "c") \
-        .replace("à", "a").replace("ö", "o").replace("ü", "u").replace("'", " ")
+        .replace("à", "a").replace("ö", "o").replace("ü", "u").replace("'", " ")

+ 11 - 3
ui/qt/dlg_meta_editor.py

@@ -1,9 +1,12 @@
 import os
+import webbrowser
 
 from PyQt5 import QtWidgets
 from PyQt5.QtGui import QIntValidator
 from path import Path
 
+from core import file_utilities
+from core.models import Track
 from core.repositories import TrackRepository
 from ui.qt.dlg_meta_editor_ui import Ui_dlgMetaEditor
 
@@ -27,14 +30,19 @@ class DlgMetaEditor(QtWidgets.QDialog):
 
         self.ui.lblPath.setText(self.track.path)
 
-        self.ui.btnOpenTrackFolder.clicked.connect(self.openTrackFolder)
+        if self.track.status != Track.STATUS_UNAVAILABLE:
+            self.ui.btnOpenTrackFolder.clicked.connect(self.openTrackFolder)
+            self.ui.lblPath.setStyleSheet("")
+        else:
+            self.ui.btnOpenTrackFolder.setEnabled(False)
+            self.ui.lblPath.setStyleSheet("QLabel { color : #cc0000; }")
 
         self.ui.btnSave.clicked.connect(self.ok)
         self.ui.btnCancel.clicked.connect(self.cancel)
 
     def openTrackFolder(self):
-        folder = Path(self.track.path)
-        os.startfile(folder)
+        folder = Path(self.track.path).parent
+        file_utilities.open_file(folder)
 
     @classmethod
     def edit(cls, parent, track=None):

+ 1 - 1
ui/qt/dlg_meta_editor.ui

@@ -23,7 +23,7 @@
    </size>
   </property>
   <property name="windowTitle">
-   <string>Dialog</string>
+   <string>Editer les informations du morceau</string>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>

+ 2 - 2
ui/qt/dlg_meta_editor_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'dlg_meta_editor.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.
@@ -105,7 +105,7 @@ class Ui_dlgMetaEditor(object):
 
     def retranslateUi(self, dlgMetaEditor):
         _translate = QtCore.QCoreApplication.translate
-        dlgMetaEditor.setWindowTitle(_translate("dlgMetaEditor", "Dialog"))
+        dlgMetaEditor.setWindowTitle(_translate("dlgMetaEditor", "Editer les informations du morceau"))
         self.label.setText(_translate("dlgMetaEditor", "Editer les informations de la piste"))
         self.label_2.setText(_translate("dlgMetaEditor", "Titre"))
         self.label_3.setText(_translate("dlgMetaEditor", "Artiste"))

+ 1 - 1
ui/qt/dlg_playlist_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'dlg_playlist.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 1 - 1
ui/qt/dlg_select_playlist_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'dlg_select_playlist.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 1 - 1
ui/qt/dlg_tag_editor_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'dlg_tag_editor.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 1 - 1
ui/qt/dlg_tag_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'dlg_tag.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 264 - 2
ui/qt/main.ui

@@ -47,7 +47,7 @@
      <number>3</number>
     </property>
     <item>
-     <layout class="QHBoxLayout" name="mainLayout" stretch="1,5">
+     <layout class="QHBoxLayout" name="mainLayout" stretch="0,5">
       <property name="spacing">
        <number>0</number>
       </property>
@@ -56,6 +56,12 @@
       </property>
       <item>
        <widget class="QListWidget" name="menu">
+        <property name="maximumSize">
+         <size>
+          <width>165</width>
+          <height>16777215</height>
+         </size>
+        </property>
         <property name="font">
          <font>
           <family>Verdana</family>
@@ -83,6 +89,12 @@
           <height>24</height>
          </size>
         </property>
+        <property name="gridSize">
+         <size>
+          <width>0</width>
+          <height>36</height>
+         </size>
+        </property>
         <property name="currentRow">
          <number>-1</number>
         </property>
@@ -402,7 +414,7 @@
                   <property name="currentIndex">
                    <number>0</number>
                   </property>
-                  <property name="placeholderText">
+                  <property name="placeholderText" stdset="0">
                    <string>(Filtrer par étiquette)</string>
                   </property>
                   <item>
@@ -731,6 +743,256 @@
                         </item>
                        </layout>
                       </item>
+                      <item>
+                       <widget class="QFrame" name="frameMissingFileWarning">
+                        <property name="minimumSize">
+                         <size>
+                          <width>0</width>
+                          <height>42</height>
+                         </size>
+                        </property>
+                        <property name="frameShape">
+                         <enum>QFrame::Box</enum>
+                        </property>
+                        <property name="frameShadow">
+                         <enum>QFrame::Raised</enum>
+                        </property>
+                        <layout class="QHBoxLayout" name="horizontalLayout_3">
+                         <property name="spacing">
+                          <number>0</number>
+                         </property>
+                         <property name="leftMargin">
+                          <number>0</number>
+                         </property>
+                         <property name="topMargin">
+                          <number>0</number>
+                         </property>
+                         <property name="rightMargin">
+                          <number>0</number>
+                         </property>
+                         <property name="bottomMargin">
+                          <number>0</number>
+                         </property>
+                         <item>
+                          <layout class="QHBoxLayout" name="hLayoutMissingFileWarning">
+                           <property name="leftMargin">
+                            <number>8</number>
+                           </property>
+                           <property name="topMargin">
+                            <number>8</number>
+                           </property>
+                           <property name="rightMargin">
+                            <number>8</number>
+                           </property>
+                           <property name="bottomMargin">
+                            <number>8</number>
+                           </property>
+                           <item>
+                            <spacer name="horizontalSpacer_4">
+                             <property name="orientation">
+                              <enum>Qt::Horizontal</enum>
+                             </property>
+                             <property name="sizeHint" stdset="0">
+                              <size>
+                               <width>40</width>
+                               <height>20</height>
+                              </size>
+                             </property>
+                            </spacer>
+                           </item>
+                           <item>
+                            <widget class="QLabel" name="label_15">
+                             <property name="minimumSize">
+                              <size>
+                               <width>24</width>
+                               <height>24</height>
+                              </size>
+                             </property>
+                             <property name="maximumSize">
+                              <size>
+                               <width>24</width>
+                               <height>23</height>
+                              </size>
+                             </property>
+                             <property name="text">
+                              <string/>
+                             </property>
+                             <property name="pixmap">
+                              <pixmap resource="rsc.qrc">:/img/rsc/invalid.png</pixmap>
+                             </property>
+                             <property name="scaledContents">
+                              <bool>true</bool>
+                             </property>
+                            </widget>
+                           </item>
+                           <item>
+                            <spacer name="horizontalSpacer_6">
+                             <property name="orientation">
+                              <enum>Qt::Horizontal</enum>
+                             </property>
+                             <property name="sizeType">
+                              <enum>QSizePolicy::Fixed</enum>
+                             </property>
+                             <property name="sizeHint" stdset="0">
+                              <size>
+                               <width>10</width>
+                               <height>20</height>
+                              </size>
+                             </property>
+                            </spacer>
+                           </item>
+                           <item>
+                            <widget class="QLabel" name="label_14">
+                             <property name="palette">
+                              <palette>
+                               <active>
+                                <colorrole role="WindowText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="Text">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="ButtonText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="PlaceholderText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="128">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                               </active>
+                               <inactive>
+                                <colorrole role="WindowText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="Text">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="ButtonText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="PlaceholderText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="128">
+                                   <red>204</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                               </inactive>
+                               <disabled>
+                                <colorrole role="WindowText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>190</red>
+                                   <green>190</green>
+                                   <blue>190</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="Text">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>190</red>
+                                   <green>190</green>
+                                   <blue>190</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="ButtonText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="255">
+                                   <red>190</red>
+                                   <green>190</green>
+                                   <blue>190</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                                <colorrole role="PlaceholderText">
+                                 <brush brushstyle="SolidPattern">
+                                  <color alpha="128">
+                                   <red>0</red>
+                                   <green>0</green>
+                                   <blue>0</blue>
+                                  </color>
+                                 </brush>
+                                </colorrole>
+                               </disabled>
+                              </palette>
+                             </property>
+                             <property name="font">
+                              <font>
+                               <weight>75</weight>
+                               <bold>true</bold>
+                              </font>
+                             </property>
+                             <property name="text">
+                              <string>Fichier introuvable</string>
+                             </property>
+                             <property name="scaledContents">
+                              <bool>true</bool>
+                             </property>
+                            </widget>
+                           </item>
+                           <item>
+                            <spacer name="horizontalSpacer_5">
+                             <property name="orientation">
+                              <enum>Qt::Horizontal</enum>
+                             </property>
+                             <property name="sizeHint" stdset="0">
+                              <size>
+                               <width>40</width>
+                               <height>20</height>
+                              </size>
+                             </property>
+                            </spacer>
+                           </item>
+                          </layout>
+                         </item>
+                        </layout>
+                       </widget>
+                      </item>
                       <item>
                        <layout class="QHBoxLayout" name="horizontalLayout_19">
                         <item>

+ 85 - 9
ui/qt/main_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'main.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.
@@ -34,6 +34,7 @@ class Ui_mainWindow(object):
         self.mainLayout.setSpacing(0)
         self.mainLayout.setObjectName("mainLayout")
         self.menu = QtWidgets.QListWidget(self.centralwidget)
+        self.menu.setMaximumSize(QtCore.QSize(165, 16777215))
         font = QtGui.QFont()
         font.setFamily("Verdana")
         font.setPointSize(12)
@@ -44,6 +45,7 @@ class Ui_mainWindow(object):
         self.menu.setDefaultDropAction(QtCore.Qt.CopyAction)
         self.menu.setAlternatingRowColors(True)
         self.menu.setIconSize(QtCore.QSize(24, 24))
+        self.menu.setGridSize(QtCore.QSize(0, 36))
         self.menu.setObjectName("menu")
         self.mainLayout.addWidget(self.menu)
         self.verticalLayout_7 = QtWidgets.QVBoxLayout()
@@ -295,6 +297,80 @@ class Ui_mainWindow(object):
         self.explorerLblTrackNumber.setObjectName("explorerLblTrackNumber")
         self.horizontalLayout_11.addWidget(self.explorerLblTrackNumber)
         self.verticalLayout_9.addLayout(self.horizontalLayout_11)
+        self.frameMissingFileWarning = QtWidgets.QFrame(self.page_6)
+        self.frameMissingFileWarning.setMinimumSize(QtCore.QSize(0, 42))
+        self.frameMissingFileWarning.setFrameShape(QtWidgets.QFrame.Box)
+        self.frameMissingFileWarning.setFrameShadow(QtWidgets.QFrame.Raised)
+        self.frameMissingFileWarning.setObjectName("frameMissingFileWarning")
+        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frameMissingFileWarning)
+        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout_3.setSpacing(0)
+        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+        self.hLayoutMissingFileWarning = QtWidgets.QHBoxLayout()
+        self.hLayoutMissingFileWarning.setContentsMargins(8, 8, 8, 8)
+        self.hLayoutMissingFileWarning.setObjectName("hLayoutMissingFileWarning")
+        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.hLayoutMissingFileWarning.addItem(spacerItem1)
+        self.label_15 = QtWidgets.QLabel(self.frameMissingFileWarning)
+        self.label_15.setMinimumSize(QtCore.QSize(24, 24))
+        self.label_15.setMaximumSize(QtCore.QSize(24, 23))
+        self.label_15.setText("")
+        self.label_15.setPixmap(QtGui.QPixmap(":/img/rsc/invalid.png"))
+        self.label_15.setScaledContents(True)
+        self.label_15.setObjectName("label_15")
+        self.hLayoutMissingFileWarning.addWidget(self.label_15)
+        spacerItem2 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+        self.hLayoutMissingFileWarning.addItem(spacerItem2)
+        self.label_14 = QtWidgets.QLabel(self.frameMissingFileWarning)
+        palette = QtGui.QPalette()
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0, 128))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.PlaceholderText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(204, 0, 0, 128))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.PlaceholderText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(190, 190, 190))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(190, 190, 190))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
+        brush = QtGui.QBrush(QtGui.QColor(190, 190, 190))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
+        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 128))
+        brush.setStyle(QtCore.Qt.SolidPattern)
+        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.PlaceholderText, brush)
+        self.label_14.setPalette(palette)
+        font = QtGui.QFont()
+        font.setBold(True)
+        font.setWeight(75)
+        self.label_14.setFont(font)
+        self.label_14.setScaledContents(True)
+        self.label_14.setObjectName("label_14")
+        self.hLayoutMissingFileWarning.addWidget(self.label_14)
+        spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.hLayoutMissingFileWarning.addItem(spacerItem3)
+        self.horizontalLayout_3.addLayout(self.hLayoutMissingFileWarning)
+        self.verticalLayout_9.addWidget(self.frameMissingFileWarning)
         self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_19.setObjectName("horizontalLayout_19")
         self.label_12 = QtWidgets.QLabel(self.page_6)
@@ -502,8 +578,8 @@ class Ui_mainWindow(object):
         self.musicFoldersRemoveButton.setIcon(icon8)
         self.musicFoldersRemoveButton.setObjectName("musicFoldersRemoveButton")
         self.horizontalLayout_7.addWidget(self.musicFoldersRemoveButton)
-        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
-        self.horizontalLayout_7.addItem(spacerItem1)
+        spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout_7.addItem(spacerItem4)
         self.musicFoldersAddButton = QtWidgets.QPushButton(self.page_5)
         self.musicFoldersAddButton.setMinimumSize(QtCore.QSize(128, 32))
         icon9 = QtGui.QIcon()
@@ -555,8 +631,8 @@ class Ui_mainWindow(object):
         self.tableTagsRemoveButton.setIcon(icon8)
         self.tableTagsRemoveButton.setObjectName("tableTagsRemoveButton")
         self.horizontalLayout_20.addWidget(self.tableTagsRemoveButton)
-        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
-        self.horizontalLayout_20.addItem(spacerItem2)
+        spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout_20.addItem(spacerItem5)
         self.tagsTableAddButton = QtWidgets.QPushButton(self.page_5)
         self.tagsTableAddButton.setMinimumSize(QtCore.QSize(128, 32))
         self.tagsTableAddButton.setMaximumSize(QtCore.QSize(128, 32))
@@ -564,8 +640,8 @@ class Ui_mainWindow(object):
         self.tagsTableAddButton.setObjectName("tagsTableAddButton")
         self.horizontalLayout_20.addWidget(self.tagsTableAddButton)
         self.verticalLayout_6.addLayout(self.horizontalLayout_20)
-        spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
-        self.verticalLayout_6.addItem(spacerItem3)
+        spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        self.verticalLayout_6.addItem(spacerItem6)
         self.horizontalLayout_5.addLayout(self.verticalLayout_6)
         self.stack.addWidget(self.page_5)
         self.verticalLayout_7.addWidget(self.stack)
@@ -577,7 +653,6 @@ class Ui_mainWindow(object):
         self.vlcFrame.setObjectName("vlcFrame")
         self.verticalLayout_7.addWidget(self.vlcFrame)
         self.mainLayout.addLayout(self.verticalLayout_7)
-        self.mainLayout.setStretch(0, 1)
         self.mainLayout.setStretch(1, 5)
         self.verticalLayout.addLayout(self.mainLayout)
         mainWindow.setCentralWidget(self.centralwidget)
@@ -608,7 +683,7 @@ class Ui_mainWindow(object):
         self.btnExplorerRefresh.setToolTip(_translate("mainWindow", "Rafraichir la liste"))
         self.explorerBtnSearch.setText(_translate("mainWindow", "..."))
         self.explorerLineSearch.setPlaceholderText(_translate("mainWindow", "Rechercher un morceau..."))
-        self.explorerFilterTags.setPlaceholderText(_translate("mainWindow", "(Filtrer par étiquette)"))
+        self.explorerFilterTags.setProperty("placeholderText", _translate("mainWindow", "(Filtrer par étiquette)"))
         self.explorerFilterTags.setItemText(0, _translate("mainWindow", "Toutes les étiquettes"))
         self.explorerTable.headerItem().setText(1, _translate("mainWindow", "2"))
         self.label_2.setText(_translate("mainWindow", "Sélectionnez une piste"))
@@ -617,6 +692,7 @@ class Ui_mainWindow(object):
         self.label_6.setText(_translate("mainWindow", "Artiste"))
         self.label_7.setText(_translate("mainWindow", "Album"))
         self.label_8.setText(_translate("mainWindow", "N°"))
+        self.label_14.setText(_translate("mainWindow", "Fichier introuvable"))
         self.label_12.setText(_translate("mainWindow", "Etiquettes"))
         self.lineSearchTags.setPlaceholderText(_translate("mainWindow", "Rechercher..."))
         item = self.explorerTrackTagsTable.horizontalHeaderItem(0)

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 448 - 1398
ui/qt/rsc_rc.py


+ 22 - 57
ui/qt/widgets/explorertable.py

@@ -1,5 +1,5 @@
 from PyQt5.QtCore import pyqtSignal
-from PyQt5.QtGui import QIcon
+from PyQt5.QtGui import QIcon, QBrush, QColor
 from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QTreeWidgetItemIterator
 
 from core import db
@@ -57,7 +57,17 @@ class ExplorerTable(QTreeWidget):
 
             item = QTreeWidgetItem(parent)
             item.setIcon(0, QIcon(":/img/rsc/music.png"))
-            item.setText(1, track.title)
+
+            if track.status != track.STATUS_UNAVAILABLE:
+                title = track.title
+                color = QColor(20, 20, 20)
+            else:
+                title = f"[Introuvable] {track.title}"
+                color = QColor(200, 20, 20)
+
+            item.setText(1, title)
+            item.setForeground(0, QBrush(color))
+            item.setForeground(1, QBrush(color))
             item.setData(2, 0, track.id)
 
         self.setUpdatesEnabled(True)
@@ -91,7 +101,13 @@ class ExplorerTable(QTreeWidget):
             track = TrackRepository().get_by_id(int(track_id))
             self.trackDoubleClicked.emit(track)
 
-    def filterBySearchText(self, searchText):
+    def filterBy(self, tag_id=None, searchText=""):
+
+        track_ids = []
+        if tag_id:
+            track_repo = TrackRepository()
+            track_ids = [t.id for t in track_repo.get_by_tag_id(tag_id)]
+
         searchText = norm_search(searchText)
 
         self.setUpdatesEnabled(False)
@@ -118,7 +134,8 @@ class ExplorerTable(QTreeWidget):
                     keys.append(grand_parent_item.text(1))
 
                 s = norm_search(" ".join(keys))
-                hide = searchText not in s
+                hide = (searchText and searchText not in s) \
+                       or (tag_id and item.data(2, 0) not in track_ids)
 
                 track_item.setHidden(hide)
 
@@ -149,56 +166,4 @@ class ExplorerTable(QTreeWidget):
         else:
             self.collapseAll()
 
-        self.setUpdatesEnabled(True)
-
-    def filterByTagId(self, tag_id):
-        track_ids = []
-        if tag_id:
-            track_repo = TrackRepository()
-            track_ids = [t.id for t in track_repo.get_by_tag_id(tag_id)]
-
-        self.setUpdatesEnabled(False)
-
-        iterator = QTreeWidgetItemIterator(self)
-        while True:
-            item = iterator.value()
-            if item is not None:
-
-                if not item.data(2, 0):
-                    # not a track
-                    item.setHidden(True)
-                    iterator += 1
-                    continue
-
-                hide = tag_id and item.data(2, 0) not in track_ids
-
-                item.setHidden(hide)
-
-                iterator += 1
-            else:
-                break
-
-        iterator = QTreeWidgetItemIterator(self)
-        while True:
-            item = iterator.value()
-            if item is not None:
-                if not item.data(2, 0) or item.isHidden():
-                    # not a track or hidden
-                    iterator += 1
-                    continue
-
-                if item.parent():
-                    item.parent().setHidden(False)
-                if item.parent() and item.parent().parent():
-                    item.parent().parent().setHidden(False)
-
-                iterator += 1
-            else:
-                break
-
-        if tag_id:
-            self.expandAll()
-        else:
-            self.collapseAll()
-
-        self.setUpdatesEnabled(True)
+        self.setUpdatesEnabled(True)

+ 1 - 1
ui/qt/widgets/frame_notes_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'widgets/frame_notes.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 1 - 1
ui/qt/widgets/vlcframe_ui.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'widgets/vlcframe.ui'
 #
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.2
 #
 # WARNING: Any manual changes made to this file will be lost when pyuic5 is
 # run again.  Do not edit this file unless you know what you are doing.

+ 29 - 18
ui/window.py

@@ -11,7 +11,7 @@ from PyQt5.QtGui import QIcon
 from PyQt5.QtWidgets import QMainWindow, QListWidgetItem, QTableWidgetItem, QFileDialog, QMessageBox
 
 from core.logging_ import Logger
-from core.models import MusicFolder, TrackTag
+from core.models import MusicFolder, TrackTag, Track
 from core.repositories import MusicFolderRepository, TrackRepository, SessionTrackRepository, SessionRepository, \
     TrackTagRepository, TagRepository
 from ui.qt.dlg_meta_editor import DlgMetaEditor
@@ -72,12 +72,12 @@ class MainWindow(QMainWindow):
         self.ui.explorerTable.trackSelected.connect(self.newTrackSelected)
         self.ui.explorerTable.trackDoubleClicked.connect(self.play_track)
         self.ui.btnExplorerRefresh.clicked.connect(self.refresh_explorer_tree)
-        self.ui.explorerLineSearch.editingFinished.connect(self.explorerSearchChanged)
-        self.ui.explorerLineSearch.textChanged.connect(lambda s: (s or self.explorerSearchChanged())) # when search bar is cleared
-        self.ui.explorerBtnSearch.clicked.connect(self.explorerSearchChanged)
+        self.ui.explorerLineSearch.editingFinished.connect(self.explorerFiltersChanged)
+        self.ui.explorerLineSearch.textChanged.connect(self.explorerFiltersChanged) # when search bar is cleared
+        self.ui.explorerBtnSearch.clicked.connect(self.explorerFiltersChanged)
 
         self.populate_explorer_filter_tags()
-        self.ui.explorerFilterTags.currentIndexChanged.connect(self.tagFilterChanged)
+        self.ui.explorerFilterTags.currentIndexChanged.connect(self.explorerFiltersChanged)
 
         self.ui.explorerTrackEdit.clicked.connect(self.showMetaEditor)
 
@@ -152,6 +152,7 @@ class MainWindow(QMainWindow):
         self.ui.explorerAddToPlaylist.setEnabled(False)
         self.ui.explorerRemoveFromPlaylist.setEnabled(False)
         self.ui.explorerTrackNotepad.setText("")
+        self.ui.frameMissingFileWarning.setVisible(False)
 
         if not track:
             return
@@ -162,19 +163,23 @@ class MainWindow(QMainWindow):
         self.update_meta()
 
         self.ui.explorerTrackNotepad.setHtml(track.note)
-
         self.ui.explorerTrackTagsTable.populate(track)
-
         self.ui.explorerTrackMetaStack.setCurrentIndex(1)
-        self.ui.explorerTrackPlay.setEnabled(True)
 
-        if type(sender) is ExplorerTable:
-            self.ui.explorerAddToPlaylist.setEnabled(True)
 
-        elif type(sender) is PlaylistTable:
-            self.ui.explorerRemoveFromPlaylist.setEnabled(True)
+        # Commands
+        if self.selected_track.status == Track.STATUS_UNAVAILABLE:
+            self.ui.frameMissingFileWarning.setVisible(True)
         else:
-            raise RuntimeError("Unknown sender")
+            self.ui.explorerTrackPlay.setEnabled(True)
+
+            if type(sender) is ExplorerTable:
+                self.ui.explorerAddToPlaylist.setEnabled(True)
+
+            elif type(sender) is PlaylistTable:
+                self.ui.explorerRemoveFromPlaylist.setEnabled(True)
+            else:
+                raise RuntimeError("Unknown sender")
 
         self.ui.explorerTable.viewport().repaint()
         self.ui.explorerPlaylist.viewport().repaint()
@@ -238,6 +243,8 @@ class MainWindow(QMainWindow):
         self.play_track(track)
 
     def play_track(self, track):
+        if not Path(track.path).exists():
+            return
         logger.info("Start playing: %s" % track)
         self.ui.vlcFrame.load_track(track)
         self.ui.vlcFrame.play()
@@ -327,9 +334,16 @@ class MainWindow(QMainWindow):
 
     def play_playlist(self, track=None):
 
+        if track.status == Track.STATUS_UNAVAILABLE:
+            track = None
+
         playlist = self.selected_playlist
         track_repo = TrackRepository()
         tracks = track_repo.get_by_session_id(playlist.id)
+        tracks = [t for t in tracks if t.status != Track.STATUS_UNAVAILABLE]
+        if not tracks:
+            return
+
         start_at = tracks.index(track) if track else 0
 
         logger.info("Start playing playlist: %s from index %s" % (playlist, start_at))
@@ -370,13 +384,10 @@ class MainWindow(QMainWindow):
         track_repo.commit()
         print('track notes saved')
 
-    def explorerSearchChanged(self):
+    def explorerFiltersChanged(self):
         searchText = self.ui.explorerLineSearch.text()
-        self.ui.explorerTable.filterBySearchText(searchText)
-
-    def tagFilterChanged(self, _):
         tag_id = int(self.ui.explorerFilterTags.currentData())
-        self.ui.explorerTable.filterByTagId(tag_id)
+        self.ui.explorerTable.filterBy(tag_id, searchText)
 
     def filesIndexed(self, tracks):
         self.statusBar().showMessage(f"{len(tracks)} fichiers indexés", 3000)

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio