Implement choose library action

This commit is contained in:
Kovid Goyal 2010-07-16 23:48:18 -06:00
parent 0ad6ab164f
commit 12a4797a6f
7 changed files with 273 additions and 79 deletions

View File

@ -0,0 +1,82 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
from PyQt4.Qt import QDialog
from calibre.gui2.dialogs.choose_library_ui import Ui_Dialog
from calibre.gui2 import error_dialog, choose_dir
from calibre.constants import filesystem_encoding
from calibre import isbytestring, patheq
from calibre.utils.config import prefs
from calibre.gui2.wizard import move_library
class ChooseLibrary(QDialog, Ui_Dialog):
def __init__(self, db, callback, parent):
QDialog.__init__(self, parent)
self.setupUi(self)
self.db = db
self.new_db = None
self.callback = callback
lp = db.library_path
if isbytestring(lp):
lp = lp.decode(filesystem_encoding)
loc = unicode(self.old_location.text()).format(lp)
self.old_location.setText(loc)
self.browse_button.clicked.connect(self.choose_loc)
def choose_loc(self, *args):
loc = choose_dir(self, 'choose library location',
_('Choose location for calibre library'))
if loc is not None:
self.location.setText(loc)
def check_action(self, ac, loc):
exists = self.db.exists_at(loc)
if patheq(loc, self.db.library_path):
error_dialog(self, _('Same as current'),
_('The location %s contains the current calibre'
' library')%loc, show=True)
return False
empty = not os.listdir(loc)
if ac == 'existing' and not exists:
error_dialog(self, _('No existing library found'),
_('There is no existing calibre library at %s')%loc,
show=True)
return False
if ac in ('new', 'move') and not empty:
error_dialog(self, _('Not empty'),
_('The folder %s is not empty. Please choose an empty'
' folder')%loc,
show=True)
return False
return True
def perform_action(self, ac, loc):
if ac in ('new', 'existing'):
prefs['library_path'] = loc
self.callback(loc)
else:
move_library(self.db.library_path, loc, self.parent(),
self.callback)
def accept(self):
action = 'move'
if self.existing_library.isChecked():
action = 'existing'
elif self.empty_library.isChecked():
action = 'new'
loc = os.path.abspath(unicode(self.location.text()).strip())
if not loc or not os.path.exists(loc) or not self.check_action(action,
loc):
return
QDialog.accept(self)
self.perform_action(action, loc)

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>602</width>
<height>245</height>
</rect>
</property>
<property name="windowTitle">
<string>Choose your calibre library</string>
</property>
<property name="windowIcon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/lt.png</normaloff>:/images/lt.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="old_location">
<property name="text">
<string>Your calibre library is currently located at {0}</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>New &amp;Location:</string>
</property>
<property name="buddy">
<cstring>location</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="location">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QRadioButton" name="existing_library">
<property name="text">
<string>Use &amp;existing library at the new location</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QRadioButton" name="empty_library">
<property name="text">
<string>&amp;Create an empty library at the new location</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QRadioButton" name="move_library">
<property name="text">
<string>&amp;Move current library to new location</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="7" column="1">
<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 row="3" column="0">
<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>
<item row="1" column="0">
<spacer name="verticalSpacer_3">
<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 row="2" column="2">
<widget class="QToolButton" name="browse_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/document_open.svg</normaloff>:/images/document_open.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../../resources/images.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -14,7 +14,7 @@ from PyQt4.Qt import QDialog, QListWidgetItem, QIcon, \
from calibre.constants import iswindows, isosx from calibre.constants import iswindows, isosx
from calibre.gui2.dialogs.config.config_ui import Ui_Dialog from calibre.gui2.dialogs.config.config_ui import Ui_Dialog
from calibre.gui2.dialogs.config.create_custom_column import CreateCustomColumn from calibre.gui2.dialogs.config.create_custom_column import CreateCustomColumn
from calibre.gui2 import choose_dir, error_dialog, config, gprefs, \ from calibre.gui2 import error_dialog, config, gprefs, \
open_url, open_local_file, \ open_url, open_local_file, \
ALL_COLUMNS, NONE, info_dialog, choose_files, \ ALL_COLUMNS, NONE, info_dialog, choose_files, \
warning_dialog, ResizableDialog, question_dialog warning_dialog, ResizableDialog, question_dialog
@ -343,9 +343,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.model = library_view.model() self.model = library_view.model()
self.db = self.model.db self.db = self.model.db
self.server = server self.server = server
path = prefs['library_path']
self.location.setText(path if path else '')
self.connect(self.browse_button, SIGNAL('clicked(bool)'), self.browse)
self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact) self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact)
input_map = prefs['input_format_order'] input_map = prefs['input_format_order']
@ -808,12 +805,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
d = CheckIntegrity(self.db, self) d = CheckIntegrity(self.db, self)
d.exec_() d.exec_()
def browse(self):
dir = choose_dir(self, 'database location dialog',
_('Select location for books'))
if dir:
self.location.setText(dir)
def accept(self): def accept(self):
mcs = unicode(self.max_cover_size.text()).strip() mcs = unicode(self.max_cover_size.text()).strip()
if not re.match(r'\d+x\d+', mcs): if not re.match(r'\d+x\d+', mcs):
@ -834,7 +825,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked()) config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
config['new_version_notification'] = bool(self.new_version_notification.isChecked()) config['new_version_notification'] = bool(self.new_version_notification.isChecked())
prefs['network_timeout'] = int(self.timeout.value()) prefs['network_timeout'] = int(self.timeout.value())
path = unicode(self.location.text())
input_cols = [unicode(self.input_order.item(i).data(Qt.UserRole).toString()) for i in range(self.input_order.count())] input_cols = [unicode(self.input_order.item(i).data(Qt.UserRole).toString()) for i in range(self.input_order.count())]
prefs['input_format_order'] = input_cols prefs['input_format_order'] = input_cols
@ -875,24 +865,13 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
val = self.opt_gui_layout.itemData(self.opt_gui_layout.currentIndex()).toString() val = self.opt_gui_layout.itemData(self.opt_gui_layout.currentIndex()).toString()
config['gui_layout'] = unicode(val) config['gui_layout'] = unicode(val)
if not path or not os.path.exists(path) or not os.path.isdir(path): if must_restart:
d = error_dialog(self, _('Invalid database location'), warning_dialog(self, _('Must restart'),
_('Invalid database location ')+path+ _('The changes you made require that Calibre be '
_('<br>Must be a directory.')) 'restarted. Please restart as soon as practical.'),
d.exec_() show=True, show_copy_button=False)
elif not os.access(path, os.W_OK): self.parent.must_restart_before_config = True
d = error_dialog(self, _('Invalid database location'), QDialog.accept(self)
_('Invalid database location.<br>Cannot write to ')+path)
d.exec_()
else:
self.database_location = os.path.abspath(path)
if must_restart:
warning_dialog(self, _('Must restart'),
_('The changes you made require that Calibre be '
'restarted. Please restart as soon as practical.'),
show=True, show_copy_button=False)
self.parent.must_restart_before_config = True
QDialog.accept(self)
class VacThread(QThread): class VacThread(QThread):

View File

@ -113,50 +113,6 @@
</property> </property>
<widget class="QWidget" name="page_3"> <widget class="QWidget" name="page_3">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="_2">
<item>
<widget class="QLabel" name="label">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>70</height>
</size>
</property>
<property name="text">
<string>&amp;Location of ebooks (The ebooks are stored in folders sorted by author and metadata is stored in the file metadata.db)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>location</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="_3">
<item>
<widget class="QLineEdit" name="location"/>
</item>
<item>
<widget class="QToolButton" name="browse_button">
<property name="toolTip">
<string>Browse for the new database location</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/mimetypes/dir.svg</normaloff>:/images/mimetypes/dir.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item> <item>
<widget class="QCheckBox" name="new_version_notification"> <widget class="QCheckBox" name="new_version_notification">
<property name="text"> <property name="text">

View File

@ -329,6 +329,7 @@ class MainWindowMixin(object):
self.tool_bar = ToolBar(all_actions, self.donate_button, self.tool_bar = ToolBar(all_actions, self.donate_button,
self.location_manager, self) self.location_manager, self)
self.addToolBar(Qt.TopToolBarArea, self.tool_bar) self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
self.tool_bar.choose_action.triggered.connect(self.choose_library)
l = self.centralwidget.layout() l = self.centralwidget.layout()
l.addWidget(self.search_bar) l.addWidget(self.search_bar)
@ -337,6 +338,12 @@ class MainWindowMixin(object):
def read_toolbar_settings(self): def read_toolbar_settings(self):
pass pass
def choose_library(self, *args):
from calibre.gui2.dialogs.choose_library import ChooseLibrary
db = self.library_view.model().db
c = ChooseLibrary(db, self.library_moved, self)
c.exec_()
def setup_actions(self): # {{{ def setup_actions(self): # {{{
all_actions = [] all_actions = []

View File

@ -18,7 +18,7 @@ from PyQt4.Qt import Qt, SIGNAL, QTimer, \
QSystemTrayIcon, QApplication, QKeySequence, QAction, \ QSystemTrayIcon, QApplication, QKeySequence, QAction, \
QMessageBox, QHelpEvent QMessageBox, QHelpEvent
from calibre import prints, patheq from calibre import prints
from calibre.constants import __appname__, isosx from calibre.constants import __appname__, isosx
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import prefs, dynamic from calibre.utils.config import prefs, dynamic
@ -27,7 +27,6 @@ from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \
gprefs, max_available_height, config, info_dialog gprefs, max_available_height, config, info_dialog
from calibre.gui2.cover_flow import CoverFlowMixin from calibre.gui2.cover_flow import CoverFlowMixin
from calibre.gui2.widgets import ProgressIndicator from calibre.gui2.widgets import ProgressIndicator
from calibre.gui2.wizard import move_library
from calibre.gui2.dialogs.scheduler import Scheduler from calibre.gui2.dialogs.scheduler import Scheduler
from calibre.gui2.update import UpdateMixin from calibre.gui2.update import UpdateMixin
from calibre.gui2.main_window import MainWindow from calibre.gui2.main_window import MainWindow
@ -389,10 +388,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
self.tags_view.recount() self.tags_view.recount()
self.create_device_menu() self.create_device_menu()
self.set_device_menu_items_state(bool(self.device_connected)) self.set_device_menu_items_state(bool(self.device_connected))
if not patheq(self.library_path, d.database_location):
newloc = d.database_location
move_library(self.library_path, newloc, self,
self.library_moved)
def library_moved(self, newloc): def library_moved(self, newloc):
if newloc is None: return if newloc is None: return

View File

@ -116,6 +116,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# missing functions # missing functions
self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter') self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter')
@classmethod
def exists_at(cls, path):
return path and os.path.exists(os.path.join(path, 'metadata.db'))
def __init__(self, library_path, row_factory=False): def __init__(self, library_path, row_factory=False):
self.field_metadata = FieldMetadata() self.field_metadata = FieldMetadata()
if not os.path.exists(library_path): if not os.path.exists(library_path):