Implement #2931 (Allow drag and drop adding of new formats)

This commit is contained in:
Kovid Goyal 2009-10-08 15:45:03 -06:00
parent 6c3dca52c8
commit 21b8b2a68a
3 changed files with 101 additions and 10 deletions

View File

@ -12,8 +12,8 @@ import time
import traceback
from datetime import datetime, timedelta
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread, QDate
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog
from PyQt4.Qt import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread, QDate, \
QPixmap, QListWidgetItem, QDialog, QListWidget
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
choose_files, choose_images, ResizableDialog
@ -80,6 +80,37 @@ class Format(QListWidgetItem):
QListWidgetItem.__init__(self, file_icon_provider().icon_from_ext(ext),
text, parent, QListWidgetItem.UserType)
class FormatList(QListWidget):
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
@classmethod
def paths_from_event(cls, event):
'''
Accept a drop event and return a list of paths that can be read from
and represent files with extensions.
'''
if event.mimeData().hasFormat('text/uri-list'):
urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()]
urls = [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)]
return [u for u in urls if os.path.splitext(u)[1][1:].lower() in cls.DROPABBLE_EXTENSIONS]
def dragEnterEvent(self, event):
if int(event.possibleActions() & Qt.CopyAction) + \
int(event.possibleActions() & Qt.MoveAction) == 0:
return
paths = self.paths_from_event(event)
if paths:
event.acceptProposedAction()
def dropEvent(self, event):
paths = self.paths_from_event(event)
event.setDropAction(Qt.CopyAction)
self.emit(SIGNAL('formats_dropped(PyQt_PyObject,PyQt_PyObject)'),
event, paths)
def dragMoveEvent(self, event):
event.acceptProposedAction()
class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
COVER_FETCH_TIMEOUT = 240 # seconds
@ -129,16 +160,21 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
def add_format(self, x):
files = choose_files(self, 'add formats dialog',
"Choose formats for " + qstring_to_unicode((self.title.text())),
[('Books', BOOK_EXTENSIONS)])
if not files:
return
for _file in files:
_("Choose formats for ") + unicode((self.title.text())),
[(_('Books'), BOOK_EXTENSIONS)])
self._add_formats(files)
def _add_formats(self, paths):
added = False
if not paths:
return added
bad_perms = []
for _file in paths:
_file = os.path.abspath(_file)
if not os.access(_file, os.R_OK):
QErrorMessage(self.window).showMessage("You do not have "+\
"permission to read the file: " + _file)
bad_perms.append(_file)
continue
_file = run_plugins_on_import(_file)
size = os.stat(_file).st_size
ext = os.path.splitext(_file)[1].lower().replace('.', '')
@ -149,6 +185,17 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
break
Format(self.formats, ext, size, path=_file)
self.formats_changed = True
added = True
if bad_perms:
error_dialog(self.window, _('You do not have '
'permission to read the following files:'),
det_msg='\n'.join(bad_perms), show=True)
return added
def formats_dropped(self, event, paths):
if self._add_formats(paths):
event.accept()
def remove_format(self, x):
rows = self.formats.selectionModel().selectedRows(0)
@ -276,6 +323,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.row = row
self.cover_data = None
self.formats_changed = False
self.formats.setAcceptDrops(True)
self.cover_changed = False
self.cpixmap = None
self.cover.setAcceptDrops(True)
@ -287,6 +335,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.select_cover)
QObject.connect(self.add_format_button, SIGNAL("clicked(bool)"), \
self.add_format)
self.connect(self.formats,
SIGNAL('formats_dropped(PyQt_PyObject,PyQt_PyObject)'),
self.formats_dropped)
QObject.connect(self.remove_format_button, SIGNAL("clicked(bool)"), \
self.remove_format)
QObject.connect(self.fetch_metadata_button, SIGNAL('clicked()'),

View File

@ -439,7 +439,7 @@
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1" rowspan="3">
<widget class="QListWidget" name="formats">
<widget class="FormatList" name="formats">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
@ -452,6 +452,9 @@
<height>130</height>
</size>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DropOnly</enum>
</property>
<property name="iconSize">
<size>
<width>64</width>
@ -703,6 +706,11 @@
<extends>QLineEdit</extends>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>FormatList</class>
<extends>QListWidget</extends>
<header location="global">calibre/gui2/widgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>title</tabstop>

View File

@ -19,6 +19,7 @@ from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
from calibre.gui2.filename_pattern_ui import Ui_Form
from calibre import fit_image
from calibre.utils.fonts import fontconfig
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.metadata.meta import metadata_from_filename
from calibre.utils.config import prefs
@ -107,6 +108,37 @@ class FilenamePattern(QWidget, Ui_Form):
IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'gif', 'png', 'bmp']
class FormatList(QListWidget):
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
@classmethod
def paths_from_event(cls, event):
'''
Accept a drop event and return a list of paths that can be read from
and represent files with extensions.
'''
if event.mimeData().hasFormat('text/uri-list'):
urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()]
urls = [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)]
return [u for u in urls if os.path.splitext(u)[1][1:].lower() in cls.DROPABBLE_EXTENSIONS]
def dragEnterEvent(self, event):
if int(event.possibleActions() & Qt.CopyAction) + \
int(event.possibleActions() & Qt.MoveAction) == 0:
return
paths = self.paths_from_event(event)
if paths:
event.acceptProposedAction()
def dropEvent(self, event):
paths = self.paths_from_event(event)
event.setDropAction(Qt.CopyAction)
self.emit(SIGNAL('formats_dropped(PyQt_PyObject,PyQt_PyObject)'),
event, paths)
def dragMoveEvent(self, event):
event.acceptProposedAction()
class ImageView(QLabel):
MAX_WIDTH = 400