Refactored top tags editor into generic TagListEditor widget

This commit is contained in:
Philipp Wolfer
2019-11-29 14:05:56 +01:00
parent edd79a6dd0
commit 9baba44c98
7 changed files with 422 additions and 307 deletions

View File

@@ -51,9 +51,6 @@ class InterfaceTopTagsOptionsPage(OptionsPage):
super().__init__(parent)
self.ui = Ui_InterfaceTopTagsOptionsPage()
self.ui.setupUi(self)
selection = self.ui.top_tags_list.selectionModel()
selection.selectionChanged.connect(self.on_selection_changed)
self.on_selection_changed([], [])
def load(self):
tags = config.setting["metadatabox_top_tags"]
@@ -69,11 +66,5 @@ class InterfaceTopTagsOptionsPage(OptionsPage):
self.ui.top_tags_list.clear()
super().restore_defaults()
def on_selection_changed(self, selected, deselected):
buttons_enabled = len(self.ui.top_tags_list.selectedIndexes()) > 0
self.ui.tags_remove_btn.setEnabled(buttons_enabled)
self.ui.tags_move_up_btn.setEnabled(buttons_enabled)
self.ui.tags_move_down_btn.setEnabled(buttons_enabled)
register_options_page(InterfaceTopTagsOptionsPage)

View File

@@ -10,7 +10,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_InterfaceTopTagsOptionsPage(object):
def setupUi(self, InterfaceTopTagsOptionsPage):
InterfaceTopTagsOptionsPage.setObjectName("InterfaceTopTagsOptionsPage")
InterfaceTopTagsOptionsPage.resize(893, 698)
InterfaceTopTagsOptionsPage.resize(418, 310)
self.vboxlayout = QtWidgets.QVBoxLayout(InterfaceTopTagsOptionsPage)
self.vboxlayout.setContentsMargins(9, 9, 9, 9)
self.vboxlayout.setSpacing(6)
@@ -18,65 +18,19 @@ class Ui_InterfaceTopTagsOptionsPage(object):
self.label = QtWidgets.QLabel(InterfaceTopTagsOptionsPage)
self.label.setObjectName("label")
self.vboxlayout.addWidget(self.label)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.top_tags_list = EditableTagListView(InterfaceTopTagsOptionsPage)
self.top_tags_list.setDragEnabled(True)
self.top_tags_list.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
self.top_tags_list = TagListEditor(InterfaceTopTagsOptionsPage)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.top_tags_list.sizePolicy().hasHeightForWidth())
self.top_tags_list.setSizePolicy(sizePolicy)
self.top_tags_list.setObjectName("top_tags_list")
self.verticalLayout_2.addWidget(self.top_tags_list)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.tags_remove_btn = QtWidgets.QPushButton(InterfaceTopTagsOptionsPage)
self.tags_remove_btn.setObjectName("tags_remove_btn")
self.horizontalLayout_2.addWidget(self.tags_remove_btn)
self.tags_add_btn = QtWidgets.QPushButton(InterfaceTopTagsOptionsPage)
self.tags_add_btn.setAccessibleName("")
self.tags_add_btn.setObjectName("tags_add_btn")
self.horizontalLayout_2.addWidget(self.tags_add_btn)
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
self.horizontalLayout.addLayout(self.verticalLayout_2)
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.tags_move_up_btn = QtWidgets.QPushButton(InterfaceTopTagsOptionsPage)
self.tags_move_up_btn.setText("")
icon = QtGui.QIcon.fromTheme("go-up")
self.tags_move_up_btn.setIcon(icon)
self.tags_move_up_btn.setObjectName("tags_move_up_btn")
self.verticalLayout.addWidget(self.tags_move_up_btn)
self.tags_move_down_btn = QtWidgets.QPushButton(InterfaceTopTagsOptionsPage)
self.tags_move_down_btn.setText("")
icon = QtGui.QIcon.fromTheme("go-down")
self.tags_move_down_btn.setIcon(icon)
self.tags_move_down_btn.setObjectName("tags_move_down_btn")
self.verticalLayout.addWidget(self.tags_move_down_btn)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem2)
self.horizontalLayout.addLayout(self.verticalLayout)
self.vboxlayout.addLayout(self.horizontalLayout)
self.vboxlayout.addWidget(self.top_tags_list)
self.retranslateUi(InterfaceTopTagsOptionsPage)
self.tags_add_btn.clicked.connect(self.top_tags_list.add_empty_row)
self.tags_remove_btn.clicked.connect(self.top_tags_list.remove_selected_rows)
self.tags_move_up_btn.clicked.connect(self.top_tags_list.move_selected_rows_up)
self.tags_move_down_btn.clicked.connect(self.top_tags_list.move_selected_rows_down)
QtCore.QMetaObject.connectSlotsByName(InterfaceTopTagsOptionsPage)
def retranslateUi(self, InterfaceTopTagsOptionsPage):
_translate = QtCore.QCoreApplication.translate
self.label.setText(_("Show the below tags above all other tags in the metadata view"))
self.tags_remove_btn.setToolTip(_("Remove selected tags"))
self.tags_remove_btn.setAccessibleName(_("Remove selected tags"))
self.tags_remove_btn.setText(_("Remove tags"))
self.tags_add_btn.setText(_("Add new tag"))
self.tags_move_up_btn.setToolTip(_("Move tag up"))
self.tags_move_up_btn.setAccessibleName(_("Move tag up"))
self.tags_move_down_btn.setToolTip(_("Move tag down"))
self.tags_move_down_btn.setAccessibleName(_("Move tag down"))
from picard.ui.taglistview import EditableTagListView
from picard.ui.widgets.taglisteditor import TagListEditor

View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Automatically generated - don't edit.
# Use `python setup.py build_ui` to update it.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_TagListEditor(object):
def setupUi(self, TagListEditor):
TagListEditor.setObjectName("TagListEditor")
TagListEditor.resize(400, 300)
self.horizontalLayout = QtWidgets.QHBoxLayout(TagListEditor)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(6)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.tag_list_view = EditableListView(TagListEditor)
self.tag_list_view.setObjectName("tag_list_view")
self.verticalLayout.addWidget(self.tag_list_view)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.tags_remove_btn = QtWidgets.QPushButton(TagListEditor)
self.tags_remove_btn.setObjectName("tags_remove_btn")
self.horizontalLayout_2.addWidget(self.tags_remove_btn)
self.tags_add_btn = QtWidgets.QPushButton(TagListEditor)
self.tags_add_btn.setObjectName("tags_add_btn")
self.horizontalLayout_2.addWidget(self.tags_add_btn)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout.addLayout(self.verticalLayout)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem1)
self.tags_move_up_btn = QtWidgets.QPushButton(TagListEditor)
self.tags_move_up_btn.setText("")
icon = QtGui.QIcon.fromTheme("go-up")
self.tags_move_up_btn.setIcon(icon)
self.tags_move_up_btn.setObjectName("tags_move_up_btn")
self.verticalLayout_2.addWidget(self.tags_move_up_btn)
self.tags_move_down_btn = QtWidgets.QPushButton(TagListEditor)
self.tags_move_down_btn.setText("")
icon = QtGui.QIcon.fromTheme("go-down")
self.tags_move_down_btn.setIcon(icon)
self.tags_move_down_btn.setObjectName("tags_move_down_btn")
self.verticalLayout_2.addWidget(self.tags_move_down_btn)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem2)
self.horizontalLayout.addLayout(self.verticalLayout_2)
self.retranslateUi(TagListEditor)
self.tags_remove_btn.clicked.connect(self.tag_list_view.remove_selected_rows)
self.tags_add_btn.clicked.connect(self.tag_list_view.add_empty_row)
self.tags_move_up_btn.clicked.connect(self.tag_list_view.move_selected_rows_up)
self.tags_move_down_btn.clicked.connect(self.tag_list_view.move_selected_rows_down)
QtCore.QMetaObject.connectSlotsByName(TagListEditor)
def retranslateUi(self, TagListEditor):
_translate = QtCore.QCoreApplication.translate
TagListEditor.setWindowTitle(_("Form"))
self.tags_remove_btn.setToolTip(_("Remove selected tags"))
self.tags_remove_btn.setAccessibleName(_("Remove selected tags"))
self.tags_remove_btn.setText(_("Remove tags"))
self.tags_add_btn.setText(_("Add new tag"))
self.tags_move_up_btn.setToolTip(_("Move tag up"))
self.tags_move_up_btn.setAccessibleName(_("Move tag up"))
self.tags_move_down_btn.setToolTip(_("Move tag down"))
self.tags_move_down_btn.setAccessibleName(_("Move tag down"))
from picard.ui.widgets.editablelistview import EditableListView

View File

@@ -22,18 +22,10 @@ from PyQt5 import (
QtWidgets,
)
from picard.util.tags import (
TAG_NAMES,
display_tag_name,
)
class EditableTagListView(QtWidgets.QListView):
class EditableListView(QtWidgets.QListView):
def __init__(self, parent=None):
super().__init__(parent)
model = TagListModel()
self.setModel(model)
self.setItemDelegate(TagItemDelegate())
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
def keyPressEvent(self, event):
@@ -60,26 +52,26 @@ class EditableTagListView(QtWidgets.QListView):
else:
super().closeEditor(editor, hint)
def add_tag(self, tag=""):
def add_item(self, value=""):
model = self.model()
row = model.rowCount()
model.insertRow(row)
index = model.createIndex(row, 0)
model.setData(index, tag)
model.setData(index, value)
return index
def clear(self):
self.model().update([])
def update(self, tags):
self.model().update(tags)
def update(self, values):
self.model().update(values)
@property
def tags(self):
return self.model().tags
def items(self):
return self.model().items
def add_empty_row(self):
index = self.add_tag()
index = self.add_item()
self.setCurrentIndex(index)
self.edit(index)
@@ -128,20 +120,23 @@ class EditableTagListView(QtWidgets.QListView):
selection.setCurrentIndex(new_index, QtCore.QItemSelectionModel.Current)
class TagListModel(QtCore.QAbstractListModel):
def __init__(self, tags=None, parent=None):
class EditableListModel(QtCore.QAbstractListModel):
def __init__(self, items=None, parent=None):
super().__init__(parent)
self._tags = [(tag, display_tag_name(tag)) for tag in tags or []]
self._items = [(item, self.get_display_name(item)) for item in items or []]
def get_display_name(self, item): # pylint: disable=no-self-use
return item
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._tags)
return len(self._items)
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid() or role not in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
return None
field = 1 if role == QtCore.Qt.DisplayRole else 0
try:
return self._tags[index.row()][field]
return self._items[index.row()][field]
except IndexError:
return None
@@ -151,11 +146,11 @@ class TagListModel(QtCore.QAbstractListModel):
i = index.row()
try:
if role == QtCore.Qt.EditRole:
display_name = display_tag_name(value) if value else value
self._tags[i] = (value, display_name)
display_name = self.get_display_name(value) if value else value
self._items[i] = (value, display_name)
elif role == QtCore.Qt.DisplayRole:
current = self._tags[i]
self._tags[i] = (current[0], value)
current = self._items[i]
self._items[i] = (current[0], value)
return True
except IndexError:
return False
@@ -174,13 +169,13 @@ class TagListModel(QtCore.QAbstractListModel):
def insertRows(self, row, count, parent=QtCore.QModelIndex()):
super().beginInsertRows(parent, row, row + count - 1)
for i in range(count):
self._tags.insert(row, ("", ""))
self._items.insert(row, ("", ""))
super().endInsertRows()
return True
def removeRows(self, row, count, parent=QtCore.QModelIndex()):
super().beginRemoveRows(parent, row, row + count - 1)
self._tags = self._tags[:row] + self._tags[row + count:]
self._items = self._items[:row] + self._items[row + count:]
super().endRemoveRows()
return True
@@ -192,13 +187,13 @@ class TagListModel(QtCore.QAbstractListModel):
def supportedDropActions():
return QtCore.Qt.MoveAction
def update(self, tags):
def update(self, items):
self.beginResetModel()
self._tags = [(tag, display_tag_name(tag)) for tag in tags]
self._items = [(item, self.get_display_name(item)) for item in items]
self.endResetModel()
def move_row(self, row, new_row):
item = self._tags[row]
item = self._items[row]
self.removeRow(row)
self.insertRow(new_row)
index = self.index(new_row, 0)
@@ -206,19 +201,5 @@ class TagListModel(QtCore.QAbstractListModel):
self.setData(index, item[1], QtCore.Qt.DisplayRole)
@property
def tags(self):
return (t[0] for t in self._tags)
class TagItemDelegate(QtWidgets.QItemDelegate):
@staticmethod
def createEditor(parent, option, index):
editor = QtWidgets.QLineEdit(parent)
completer = QtWidgets.QCompleter(TAG_NAMES.keys(), parent)
def complete(text):
parent.setFocus()
completer.activated.connect(complete)
editor.setCompleter(completer)
return editor
def items(self):
return (t[0] for t in self._items)

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2019 Philipp Wolfer
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt5 import QtWidgets
from picard.util.tags import (
TAG_NAMES,
display_tag_name,
)
from picard.ui.ui_widget_taglisteditor import Ui_TagListEditor
from picard.ui.widgets.editablelistview import EditableListModel
class TagListEditor(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
self.ui = Ui_TagListEditor()
self.ui.setupUi(self)
list_view = self.ui.tag_list_view
model = TagListModel()
list_view.setModel(model)
list_view.setItemDelegate(TagItemDelegate())
selection = list_view.selectionModel()
selection.selectionChanged.connect(self.on_selection_changed)
self.on_selection_changed([], [])
def on_selection_changed(self, selected, deselected):
buttons_enabled = len(self.ui.tag_list_view.selectedIndexes()) > 0
self.ui.tags_remove_btn.setEnabled(buttons_enabled)
self.ui.tags_move_up_btn.setEnabled(buttons_enabled)
self.ui.tags_move_down_btn.setEnabled(buttons_enabled)
def clear(self):
self.ui.tag_list_view.update([])
def update(self, tags):
self.ui.tag_list_view.update(tags)
@property
def tags(self):
return self.ui.tag_list_view.tags
class TagListModel(EditableListModel):
def get_display_name(self, item):
return display_tag_name(item)
class TagItemDelegate(QtWidgets.QItemDelegate):
@staticmethod
def createEditor(parent, option, index):
editor = QtWidgets.QLineEdit(parent)
completer = QtWidgets.QCompleter(TAG_NAMES.keys(), parent)
def complete(text):
parent.setFocus()
completer.activated.connect(complete)
editor.setCompleter(completer)
return editor

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>893</width>
<height>698</height>
<width>418</width>
<height>310</height>
</rect>
</property>
<layout class="QVBoxLayout">
@@ -34,207 +34,25 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="EditableTagListView" name="top_tags_list">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<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="QPushButton" name="tags_remove_btn">
<property name="toolTip">
<string>Remove selected tags</string>
</property>
<property name="accessibleName">
<string>Remove selected tags</string>
</property>
<property name="text">
<string>Remove tags</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tags_add_btn">
<property name="accessibleName">
<string/>
</property>
<property name="text">
<string>Add new tag</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="tags_move_up_btn">
<property name="toolTip">
<string>Move tag up</string>
</property>
<property name="accessibleName">
<string>Move tag up</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-up">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tags_move_down_btn">
<property name="toolTip">
<string>Move tag down</string>
</property>
<property name="accessibleName">
<string>Move tag down</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-down">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
<widget class="TagListEditor" name="top_tags_list" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>EditableTagListView</class>
<extends>QListView</extends>
<header>picard.ui.taglistview</header>
<slots>
<slot>add_empty_row()</slot>
<slot>remove_selected_rows()</slot>
<slot>move_selected_rows_up()</slot>
<slot>move_selected_rows_down()</slot>
</slots>
<class>TagListEditor</class>
<extends>QWidget</extends>
<header>picard.ui.widgets.taglisteditor</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>tags_add_btn</sender>
<signal>clicked()</signal>
<receiver>top_tags_list</receiver>
<slot>add_empty_row()</slot>
<hints>
<hint type="sourcelabel">
<x>804</x>
<y>673</y>
</hint>
<hint type="destinationlabel">
<x>428</x>
<y>343</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_remove_btn</sender>
<signal>clicked()</signal>
<receiver>top_tags_list</receiver>
<slot>remove_selected_rows()</slot>
<hints>
<hint type="sourcelabel">
<x>716</x>
<y>673</y>
</hint>
<hint type="destinationlabel">
<x>428</x>
<y>343</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_move_up_btn</sender>
<signal>clicked()</signal>
<receiver>top_tags_list</receiver>
<slot>move_selected_rows_up()</slot>
<hints>
<hint type="sourcelabel">
<x>867</x>
<y>344</y>
</hint>
<hint type="destinationlabel">
<x>428</x>
<y>343</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_move_down_btn</sender>
<signal>clicked()</signal>
<receiver>top_tags_list</receiver>
<slot>move_selected_rows_down()</slot>
<hints>
<hint type="sourcelabel">
<x>867</x>
<y>374</y>
</hint>
<hint type="destinationlabel">
<x>428</x>
<y>343</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

220
ui/widget_taglisteditor.ui Normal file
View File

@@ -0,0 +1,220 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TagListEditor</class>
<widget class="QWidget" name="TagListEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</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="QVBoxLayout" name="verticalLayout">
<item>
<widget class="EditableListView" name="tag_list_view"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<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="QPushButton" name="tags_remove_btn">
<property name="toolTip">
<string>Remove selected tags</string>
</property>
<property name="accessibleName">
<string>Remove selected tags</string>
</property>
<property name="text">
<string>Remove tags</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tags_add_btn">
<property name="text">
<string>Add new tag</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="tags_move_up_btn">
<property name="toolTip">
<string>Move tag up</string>
</property>
<property name="accessibleName">
<string>Move tag up</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-up"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tags_move_down_btn">
<property name="toolTip">
<string>Move tag down</string>
</property>
<property name="accessibleName">
<string>Move tag down</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-down"/>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>EditableListView</class>
<extends>QListView</extends>
<header>picard.ui.widgets.editablelistview</header>
<slots>
<slot>add_empty_row()</slot>
<slot>remove_selected_rows()</slot>
<slot>move_selected_rows_up()</slot>
<slot>move_selected_rows_down()</slot>
</slots>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>tags_remove_btn</sender>
<signal>clicked()</signal>
<receiver>tag_list_view</receiver>
<slot>remove_selected_rows()</slot>
<hints>
<hint type="sourcelabel">
<x>182</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>155</x>
<y>133</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_add_btn</sender>
<signal>clicked()</signal>
<receiver>tag_list_view</receiver>
<slot>add_empty_row()</slot>
<hints>
<hint type="sourcelabel">
<x>269</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>155</x>
<y>133</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_move_up_btn</sender>
<signal>clicked()</signal>
<receiver>tag_list_view</receiver>
<slot>move_selected_rows_up()</slot>
<hints>
<hint type="sourcelabel">
<x>384</x>
<y>134</y>
</hint>
<hint type="destinationlabel">
<x>181</x>
<y>133</y>
</hint>
</hints>
</connection>
<connection>
<sender>tags_move_down_btn</sender>
<signal>clicked()</signal>
<receiver>tag_list_view</receiver>
<slot>move_selected_rows_down()</slot>
<hints>
<hint type="sourcelabel">
<x>384</x>
<y>164</y>
</hint>
<hint type="destinationlabel">
<x>181</x>
<y>133</y>
</hint>
</hints>
</connection>
</connections>
</ui>