def get_pixmap(icon_name): ''' Retrieve a QPixmap for the named image Any icons belonging to the plugin must be prefixed with 'images/' ''' global plugin_icon_resources, plugin_name if not icon_name.startswith('images/'): # We know this is definitely not an icon belonging to this plugin pixmap = QPixmap() pixmap.load(I(icon_name)) return pixmap # Check to see whether the icon exists as a Calibre resource # This will enable skinning if the user stores icons within a folder like: # ...\AppData\Roaming\calibre\resources\images\Plugin Name\ if plugin_name: local_images_dir = get_local_images_dir(plugin_name) local_image_path = os.path.join(local_images_dir, icon_name.replace('images/', '')) if os.path.exists(local_image_path): pixmap = QPixmap() pixmap.load(local_image_path) return pixmap # As we did not find an icon elsewhere, look within our zip resources if icon_name in plugin_icon_resources: pixmap = QPixmap() pixmap.loadFromData(plugin_icon_resources[icon_name]) return pixmap return None
def files_dropped_on_book(self, event, paths, cid=None): accept = False if self.gui.current_view() is not self.gui.library_view: return db = self.gui.library_view.model().db cover_changed = False current_idx = self.gui.library_view.currentIndex() if cid is None: if not current_idx.isValid(): return cid = db.id(current_idx.row()) if cid is None else cid for path in paths: ext = os.path.splitext(path)[1].lower() if ext: ext = ext[1:] if ext in IMAGE_EXTENSIONS: pmap = QPixmap() pmap.load(path) if not pmap.isNull(): accept = True db.set_cover(cid, pmap) cover_changed = True elif ext in BOOK_EXTENSIONS: db.add_format_with_hooks(cid, ext, path, index_is_id=True) accept = True if accept and event is not None: event.accept() if current_idx.isValid(): self.gui.library_view.model().current_changed(current_idx, current_idx) if cover_changed: if self.gui.cover_flow: self.gui.cover_flow.dataChanged()
def files_dropped_on_book(self, event, paths, cid=None): accept = False if self.gui.current_view() is not self.gui.library_view: return db = self.gui.library_view.model().db cover_changed = False current_idx = self.gui.library_view.currentIndex() if cid is None: if not current_idx.isValid(): return cid = db.id(current_idx.row()) if cid is None else cid for path in paths: ext = os.path.splitext(path)[1].lower() if ext: ext = ext[1:] if ext in IMAGE_EXTENSIONS: pmap = QPixmap() pmap.load(path) if not pmap.isNull(): accept = True db.set_cover(cid, pmap) cover_changed = True elif ext in BOOK_EXTENSIONS: db.add_format_with_hooks(cid, ext, path, index_is_id=True) accept = True if accept and event is not None: event.accept() if current_idx.isValid(): self.gui.library_view.model().current_changed( current_idx, current_idx) if cover_changed: if self.gui.cover_flow: self.gui.cover_flow.dataChanged()
def _setLangIcons(self): itemcount = self.window.cmbx_lang.count() for i in range(0, itemcount + 1): if self.window.cmbx_lang.itemText(i) == u'English': path = './Resources/FlagsIcons/USA.png' elif self.window.cmbx_lang.itemText(i) == u'Русский': path = './Resources/FlagsIcons/Russia.png' elif self.window.cmbx_lang.itemText(i) == u'Română': path = './Resources/FlagsIcons/Moldova.png' img = QPixmap() img.load(path) icon = QIcon(img) self.window.cmbx_lang.setItemIcon(i, icon)
def render_images(self, outpath, mi, items): printer = get_pdf_printer(self.opts, for_comic=True, output_file_name=outpath) printer.setDocName(mi.title) painter = QPainter(printer) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) for i, imgpath in enumerate(items): self.log("Rendering image:", i) p = QPixmap() p.load(imgpath) if not p.isNull(): if i > 0: printer.newPage() draw_image_page(printer, painter, p) else: self.log.warn("Failed to load image", i) painter.end()
def files_dropped_on_book(self, event, paths, cid=None, do_confirm=True): accept = False if self.gui.current_view() is not self.gui.library_view: return db = self.gui.library_view.model().db cover_changed = False current_idx = self.gui.library_view.currentIndex() if cid is None: if not current_idx.isValid(): return cid = db.id(current_idx.row()) if cid is None else cid formats = [] for path in paths: ext = os.path.splitext(path)[1].lower() if ext: ext = ext[1:] if ext in IMAGE_EXTENSIONS: pmap = QPixmap() pmap.load(path) if not pmap.isNull(): accept = True db.set_cover(cid, pmap) cover_changed = True elif ext in BOOK_EXTENSIONS: formats.append((ext, path)) accept = True if accept and event is not None: event.accept() if do_confirm and formats: if not confirm(_( 'You have dropped some files onto the book <b>%s</b>. This will' ' add or replace the files for this book. Do you want to proceed?' ) % db.title(cid, index_is_id=True), 'confirm_drop_on_book', parent=self.gui): formats = [] for ext, path in formats: db.add_format_with_hooks(cid, ext, path, index_is_id=True) if current_idx.isValid(): self.gui.library_view.model().current_changed( current_idx, current_idx) if cover_changed: if self.gui.cover_flow: self.gui.cover_flow.dataChanged()
def __init__(self, parent, icon_name, title): QHBoxLayout.__init__(self) title_font = QFont() title_font.setPointSize(16) title_image_label = QLabel(parent) pixmap = QPixmap() pixmap.load(I(icon_name)) if pixmap is None: error_dialog(parent, _('Restart required'), _('You must restart Calibre before using this plugin!'), show=True) else: title_image_label.setPixmap(pixmap) title_image_label.setMaximumSize(32, 32) title_image_label.setScaledContents(True) self.addWidget(title_image_label) shelf_label = QLabel(title, parent) shelf_label.setFont(title_font) self.addWidget(shelf_label) self.insertStretch(-1)
def get_pixmap(icon_name): ''' Retrieve a QPixmap for the named image Any zipped icons belonging to the plugin must be prefixed with 'images/' ''' global plugin_icon_resources if not icon_name.startswith('images/'): # We know this is definitely not an icon belonging to this plugin pixmap = QPixmap() pixmap.load(I(icon_name)) return pixmap # As we did not find an icon elsewhere, look within our zip resources if icon_name in plugin_icon_resources: pixmap = QPixmap() pixmap.loadFromData(plugin_icon_resources[icon_name]) return pixmap return None
def get_pixmap(icon_name): """ Retrieve a QPixmap for the named image Any zipped icons belonging to the plugin must be prefixed with 'images/' """ global plugin_icon_resources if not icon_name.startswith("images/"): # We know this is definitely not an icon belonging to this plugin pixmap = QPixmap() pixmap.load(I(icon_name)) return pixmap # As we did not find an icon elsewhere, look within our zip resources if icon_name in plugin_icon_resources: pixmap = QPixmap() pixmap.loadFromData(plugin_icon_resources[icon_name]) return pixmap return None
def files_dropped_on_book(self, event, paths, cid=None, do_confirm=True): accept = False if self.gui.current_view() is not self.gui.library_view: return db = self.gui.library_view.model().db cover_changed = False current_idx = self.gui.library_view.currentIndex() if cid is None: if not current_idx.isValid(): return cid = db.id(current_idx.row()) if cid is None else cid formats = [] for path in paths: ext = os.path.splitext(path)[1].lower() if ext: ext = ext[1:] if ext in IMAGE_EXTENSIONS: pmap = QPixmap() pmap.load(path) if not pmap.isNull(): accept = True db.set_cover(cid, pmap) cover_changed = True elif ext in BOOK_EXTENSIONS: formats.append((ext, path)) accept = True if accept and event is not None: event.accept() if do_confirm and formats: if not confirm( _('You have dropped some files onto the book <b>%s</b>. This will' ' add or replace the files for this book. Do you want to proceed?') % db.title(cid, index_is_id=True), 'confirm_drop_on_book', parent=self.gui): formats = [] for ext, path in formats: db.add_format_with_hooks(cid, ext, path, index_is_id=True) if current_idx.isValid(): self.gui.library_view.model().current_changed(current_idx, current_idx) if cover_changed: if self.gui.cover_flow: self.gui.cover_flow.dataChanged()
def render_images(self, outpath, mi, items): printer = get_pdf_printer(self.opts, for_comic=True, output_file_name=outpath) printer.setDocName(mi.title) painter = QPainter(printer) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) for i, imgpath in enumerate(items): self.log('Rendering image:', i) p = QPixmap() p.load(imgpath) if not p.isNull(): if i > 0: printer.newPage() draw_image_page(printer, painter, p) else: self.log.warn('Failed to load image', i) painter.end()
def render_images(self, outpath, mi, items): printer = get_pdf_printer(self.opts, for_comic=True, output_file_name=outpath) printer.setDocName(mi.title) printer.setCreator(u'%s [%s]'%(__appname__, __version__)) # Seems to be no way to set author painter = QPainter(printer) painter.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform) for i, imgpath in enumerate(items): self.log('Rendering image:', i) p = QPixmap() p.load(imgpath) if not p.isNull(): if i > 0: printer.newPage() draw_image_page(printer, painter, p) else: self.log.warn('Failed to load image', i) painter.end()
def _fetch_marvin_cover(border_width=0): ''' Retrieve LargeCoverJpg from cache ''' #self._log_location('border_width: {0}'.format(border_width)) con = sqlite3.connect(self.marvin_db_path) with con: con.row_factory = sqlite3.Row # Fetch Hash from mainDb cover_cur = con.cursor() cover_cur.execute('''SELECT Hash FROM Books WHERE ID = '{0}' '''.format(self.book_id)) row = cover_cur.fetchone() book_hash = row[b'Hash'] large_covers_subpath = self.connected_device._cover_subpath(size="large") cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash]) stats = self.parent.ios.exists(cover_path) if stats: self._log("fetching large cover from cache") #self._log("cover size: {:,} bytes".format(int(stats['st_size']))) cover_bytes = self.parent.ios.read(cover_path, mode='rb') m_image = QImage() m_image.loadFromData(cover_bytes) if border_width: # Construct a QPixmap with oversized yellow background m_image = m_image.scaledToHeight( self.COVER_ICON_SIZE - border_width * 2, Qt.SmoothTransformation) self.m_pixmap = QPixmap( QSize(m_image.width() + border_width * 2, m_image.height() + border_width * 2)) m_painter = QPainter(self.m_pixmap) m_painter.setRenderHints(m_painter.Antialiasing) m_painter.fillRect(self.m_pixmap.rect(), self.MISMATCH_COLOR) m_painter.drawImage(border_width, border_width, m_image) else: m_image = m_image.scaledToHeight( self.COVER_ICON_SIZE, Qt.SmoothTransformation) self.m_pixmap = QPixmap( QSize(m_image.width(), m_image.height())) m_painter = QPainter(self.m_pixmap) m_painter.setRenderHints(m_painter.Antialiasing) m_painter.drawImage(0, 0, m_image) self.marvin_cover.setPixmap(self.m_pixmap) else: # No cover available, use generic self._log("No cached cover, using generic") pixmap = QPixmap() pixmap.load(I('book.png')) pixmap = pixmap.scaled(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE, aspectRatioMode=Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) self.marvin_cover.setPixmap(pixmap)
class LetsShareBooksDialog(QDialog): started_calibre_web_server = QtCore.pyqtSignal() calibre_didnt_start = QtCore.pyqtSignal() established_ssh_tunnel = QtCore.pyqtSignal() def __init__(self, gui, icon, do_user_config, qaction, us): QDialog.__init__(self, gui) self.main_gui = gui self.do_user_config = do_user_config self.qaction = qaction self.us = us self.initial = True self.lsb_url_text = 'Be a librarian. Share your library.' self.url_label_tooltip = '<<<< Be a librarian. Click on Start sharing button.<<<<' self.lsb_url = 'nourl' if prefs['librarian'] == 'l' or prefs['librarian'] == '': self.librarian = get_libranon() else: self.librarian = prefs['librarian'] self.metadata_thread = MetadataLibThread(self.librarian) self.check_connection = ConnectionCheck() self.clip = QApplication.clipboard() self.pxmp = QPixmap() self.pxmp.load('images/icon_connected.png') self.icon_connected = QIcon(self.pxmp) self.setStyleSheet(""" QDialog { background-color: white; } QPushButton { font-size: 16px; border-style: solid; border-color: red; font-family:'BitstreamVeraSansMono',Consolas,monospace; text-transform: uppercase; } QPushButton#arrow { border-width: 16px; border-right-color:white; padding: -10px; color:red; } QPushButton#url { background-color: red; min-width: 460px; color: white; text-align: left; } QPushButton#url:hover { background-color: white; color: red; } QPushButton#share { background-color: red; color: white; margin-right: 10px; } QPushButton#share:hover { background-color: white; color: red; } QPushButton#url2 { color: #222; text-align: left; } QPushButton#url2:hover { color: red; } QLineEdit#edit { background-color: white; color: black; font-size: 16px; border-style: solid; border-color: red; font-family:'BitstreamVeraSansMono',Consolas,monospace; text-transform: uppercase; } """) self.ll = QVBoxLayout() #self.ll.setSpacing(1) self.l = QHBoxLayout() self.l.setSpacing(0) self.l.setMargin(0) #self.l.setContentsMargins(0,0,0,0) self.w = QWidget() self.w.setLayout(self.l) self.setLayout(self.ll) self.setWindowIcon(icon) self.debug_label = QLabel() self.ll.addWidget(self.debug_label) self.debug_label.show() self.lets_share_button = QPushButton() self.lets_share_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.lets_share_button.setObjectName("share") #self.lets_share_button.clicked.connect(self.lets_share) self.l.addWidget(self.lets_share_button) self.url_label = QPushButton() self.url_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.url_label.setObjectName("url") #self.url_label.clicked.connect(self.open_url) self.l.addWidget(self.url_label) self.arrow_button = QPushButton("_____") self.arrow_button.setObjectName("arrow") self.l.addWidget(self.arrow_button) self.ll.addWidget(self.w) self.ll.addSpacing(5) self.libranon_layout = QHBoxLayout() self.libranon_layout.setSpacing(0) self.libranon_layout.setMargin(0) #self.l.setContentsMargins(0,0,0,0) self.libranon_container = QWidget() self.libranon_container.setLayout(self.libranon_layout) self.edit = QLineEdit() self.edit.setObjectName("edit") self.edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.edit.setToolTip("Change your librarian name") self.edit.setText(self.librarian) #self.edit.textChanged.connect(self.handle_text_changed) self.save_libranon = QPushButton("librarian:") self.save_libranon.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.save_libranon.setObjectName("share") self.save_libranon.setToolTip("Save your librarian name") self.libranon_layout.addWidget(self.save_libranon) self.libranon_layout.addWidget(self.edit) self.save_libranon.clicked.connect(self.save_librarian) self.ll.addWidget(self.libranon_container) self.ll.addSpacing(10) self.chat_button = QPushButton("Chat room: https://chat.memoryoftheworld.org") #self.chat_button.hovered.connect(self.setCursorToHand) self.chat_button.setObjectName("url2") self.chat_button.setToolTip('Meetings every thursday at 23:59 (central eruopean time)') self.chat_button.clicked.connect(functools.partial(self.open_url, "https://chat.memoryoftheworld.org/?nick={}".format(self.librarian.lower().replace(" ", "_")))) self.ll.addWidget(self.chat_button) self.about_project_button = QPushButton('Public Library: http://www.memoryoftheworld.org') self.about_project_button.setObjectName("url2") self.about_project_button.setToolTip('When everyone is librarian, library is everywhere.') self.metadata_thread.uploaded.connect(lambda: self.render_library_button("{}://library.{}".format(prefs['server_prefix'], prefs['lsb_server']), "Building together real-time p2p library infrastructure.")) self.ll.addWidget(self.about_project_button) self.debug_log = QListWidget() self.ll.addWidget(self.debug_log) self.debug_log.addItem("Initiatied!") self.debug_log.hide() from PyQt4 import QtWebKit self.webview = QtWebKit.QWebView() self.webview.setMaximumWidth(680) self.webview.setMaximumHeight(400) self.webview.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.webview.setUrl(QtCore.QUrl( "https://chat.memoryoftheworld.org/?nick={}".format(self.librarian.lower().replace(" ", "_")))) self.ll.addWidget(self.webview) #self.webview.hide() #- check if there is a new version of plugin ---------------------------------------------- self.plugin_url = "https://github.com/marcellmars/letssharebooks/raw/master/calibreletssharebooks/letssharebooks_calibre.zip" self.running_version = ".".join(map(str, lsb.version)) try: r = requests.get('https://raw.github.com/marcellmars/letssharebooks/master/calibreletssharebooks/_version', timeout=3) self.latest_version = r.text[-1] except: self.latest_version = "0.0.0" self.upgrade_button = QPushButton('Please download and upgrade from {0} to {1} version of plugin.'.format(self.us.running_version, self.latest_version)) self.upgrade_button.setObjectName("url2") self.upgrade_button.setToolTip('Running latest version you make developers happy') self.upgrade_button.clicked.connect(functools.partial(self.open_url, self.plugin_url)) version_list = [self.us.running_version, self.us.latest_version] version_list.sort(key=lambda s: map(int, s.split('.'))) if self.us.running_version != self.us.latest_version: if self.us.running_version == version_list[0]: self.ll.addSpacing(20) self.ll.addWidget(self.upgrade_button) #------------------------------------------------------------------------------------------ self.resize(self.sizeHint()) #- parsing/tee log file ------------------------------------------------------------------- self.se = open("/tmp/lsb.log", "w+b") #self.se = tempfile.NamedTemporaryFile() self.so = self.se sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) os.dup2(self.so.fileno(), sys.stdout.fileno()) os.dup2(self.se.fileno(), sys.stderr.fileno()) #- state machine -------------------------------------------------------------------------- self.machine = QtCore.QStateMachine() self.on = QtCore.QState() self.on.setObjectName("on") self.on.entered.connect(lambda: self.render_lsb_button("Start sharing", self.lsb_url_text)) self.calibre_web_server = QtCore.QState() self.calibre_web_server.setObjectName("calibre_web_server") self.calibre_web_server.entered.connect(self.start_calibre_server) self.calibre_web_server.entered.connect(lambda: self.render_lsb_button("Stop sharing", self.lsb_url_text)) self.calibre_web_server.assignProperty(self.debug_label, 'text', 'Starting Calibre web server...') self.ssh_server = QtCore.QState() self.ssh_server.setObjectName("ssh_server") self.ssh_server.entered.connect(lambda: self.render_lsb_button("Stop sharing", "Connecting...")) self.ssh_server.entered.connect(self.establish_ssh_server) self.ssh_server.assignProperty(self.debug_label, 'text', 'Establishing SSH tunnel...') self.ssh_server_established = QtCore.QState() self.ssh_server_established.setObjectName("ssh_server_established") self.ssh_server_established.entered.connect(lambda: self.render_lsb_button("Stop sharing", self.lsb_url_text)) self.ssh_server_established.entered.connect(self.check_connections) self.ssh_server_established.assignProperty(self.debug_label, 'text', 'Established SSH tunnel...') self.url_label_clicked = QtCore.QState() self.url_label_clicked.setObjectName("url_label_clicked") self.url_label_clicked.entered.connect(lambda: self.open_url(self.lsb_url)) self.url_label_clicked.assignProperty(self.debug_label, 'text', 'URL label clicked!') self.about_project_clicked = QtCore.QState() self.about_project_clicked.setObjectName("about_project_clicked") self.about_project_clicked.entered.connect(lambda: self.open_url("{}://library.{}".format(prefs['server_prefix'], prefs['lsb_server']))) self.about_project_clicked.assignProperty(self.debug_label, 'text', 'about_project_button clicked!') self.library_state_changed = QtCore.QState() self.library_state_changed.entered.connect(lambda: self.render_library_button("Uploading library metadata...", "Sharing with the others who share their libraries now...")) self.library_state_changed.setObjectName("library_state_changed") self.library_state_changed.entered.connect(self.sync_metadata) self.off = QtCore.QState() self.off.setObjectName("off") self.off.entered.connect(lambda: self.disconnect_all()) self.off.assignProperty(self.debug_label, 'text', 'Start again...') self.on.addTransition(self.lets_share_button.clicked, self.calibre_web_server) self.calibre_web_server.addTransition(self.lets_share_button.clicked, self.off) self.calibre_web_server.addTransition(self.calibre_didnt_start, self.off) self.calibre_web_server.addTransition(self.started_calibre_web_server, self.ssh_server) self.ssh_server.addTransition(self.lets_share_button.clicked, self.off) self.ssh_server.addTransition(self.check_connection.lost_connection, self.off) self.ssh_server.addTransition(self.established_ssh_tunnel, self.ssh_server_established) self.ssh_server_established.addTransition(self.lets_share_button.clicked, self.off) self.ssh_server_established.addTransition(self.url_label.clicked, self.url_label_clicked) self.ssh_server_established.addTransition(self.about_project_button.clicked, self.about_project_clicked) self.ssh_server_established.addTransition(self.check_connection.lost_connection, self.off) self.ssh_server_established.addTransition(self.us.library_changed, self.library_state_changed) self.url_label_clicked.addTransition(self.ssh_server_established) self.about_project_clicked.addTransition(self.ssh_server_established) self.library_state_changed.addTransition(self.metadata_thread.uploaded, self.ssh_server_established) self.library_state_changed.addTransition(self.metadata_thread.upload_error, self.off) self.library_state_changed.addTransition(self.lets_share_button.clicked, self.off) self.library_state_changed.addTransition(self.url_label.clicked, self.url_label_clicked) self.off.addTransition(self.on) self.machine.addState(self.on) self.machine.addState(self.calibre_web_server) self.machine.addState(self.ssh_server) self.machine.addState(self.ssh_server_established) self.machine.addState(self.url_label_clicked) self.machine.addState(self.about_project_clicked) self.machine.addState(self.library_state_changed) self.machine.addState(self.off) self.machine.setInitialState(self.on) self.machine.start() #------------------------------------------------------------------------------------------ def sql_db_changed(self, event, ids): # this could be used for better update on added/removed books if not self.metadata_thread.isRunning(): self.sync_metadata() else: print("metadata_thread is running! no sync!") def sync_metadata(self): from calibre.gui2.ui import get_gui try: del self.sql_db except: pass self.sql_db = get_gui().current_db self.sql_db.add_listener(self.sql_db_changed) self.metadata_thread.sql_db = self.sql_db self.metadata_thread.port = self.port self.metadata_thread.uploaded.connect(lambda: self.debug_log.addItem("uploaded!")) self.metadata_thread.upload_error.connect(lambda: self.debug_log.addItem("upload_ERROR!")) self.metadata_thread.start() def check_connections(self): #self.webview.show() if self.initial: print("initial!") self.us.library_changed_emit() self.initial = False self.qaction.setIcon(get_icon('images/icon_connected.png')) self.check_connection.add_urls(["http://*****:*****@{2} -R {0}:localhost:{1} -P 722".format(self.port, self.calibre_server_port, prefs['lsb_server']), shell=True) self.lsb_url = "{}://www{}.{}".format(prefs['server_prefix'], self.port, prefs['lsb_server']) self.lsb_url_text = "Go to: {}".format(self.lsb_url) QTimer.singleShot(3000, self.established_ssh_tunnel.emit) else: self.ssh_proc = subprocess.Popen(['ssh', '-T', '-N', '-g', '-o', 'TCPKeepAlive=yes', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no','-o', 'ServerAliveINterval=60', prefs['lsb_server'], '-l', 'tunnel', '-R', '0:localhost:{0}'.format(self.calibre_server_port), '-p', '722']) if self.ssh_proc: def parse_log(): gotcha = False try: self.se.seek(0) result = self.se.readlines() self.se.seek(0) self.se.truncate() for line in result: m = re.match("^Allocated port (.*) for .*", line) try: self.port = m.groups()[0] self.lsb_url = '{}://www{}.{}'.format(prefs['server_prefix'], self.port, prefs['lsb_server']) self.lsb_url_text = "Go to: {0}".format(self.lsb_url) self.url_label_tooltip = 'Copy URL to clipboard and check it out in a browser!' self.established_ssh_tunnel.emit() gotcha = True except: pass finally: if not gotcha: QTimer.singleShot(500, parse_log) parse_log() def start_calibre_server(self): if self.main_gui.content_server is None: self.main_gui.start_content_server() opts, args = server_config().option_parser().parse_args(['calibre-server']) self.calibre_server_port = opts.port self.started_calibre_web_server.emit() else: self.calibre_didnt_start.emit() def config(self): self.do_user_config(parent=self) self.label.setText(prefs['lsb_server']) def save_librarian(self): print('librarian {} saved!'.format(str(self.edit.text()))) if self.edit.text() != "" and self.edit.text() != "l": prefs['librarian'] = str(self.edit.text()) else: prefs['librarian'] = get_libranon() self.edit.setText(prefs['librarian']) def open_url(self, url): self.clip.setText(url) webbrowser.open(url) def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: pass def closeEvent(self, e): print("close popup!") self.hide()
class GuiRunner(QObject): '''Make sure an event loop is running before starting the main work of initialization''' def __init__(self, opts, args, actions, listener, app, gui_debug=None): self.startup_time = time.time() self.opts, self.args, self.listener, self.app = opts, args, listener, app self.gui_debug = gui_debug self.actions = actions self.main = None QObject.__init__(self) self.splash_screen = None self.timer = QTimer.singleShot(1, self.initialize) if DEBUG: prints('Starting up...') def start_gui(self, db): from calibre.gui2.ui import Main main = self.main = Main(self.opts, gui_debug=self.gui_debug) if self.splash_screen is not None: self.splash_screen.showMessage(_('Initializing user interface...')) with gprefs: # Only write gui.json after initialization is complete main.initialize(self.library_path, db, self.listener, self.actions) if self.splash_screen is not None: self.splash_screen.finish(main) if DEBUG: prints( 'Started up in %.2f seconds' % (time.time() - self.startup_time), 'with', len(db.data), 'books') add_filesystem_book = partial( main.iactions['Add Books'].add_filesystem_book, allow_device=False) sys.excepthook = main.unhandled_exception if len(self.args) > 1: files = [ os.path.abspath(p) for p in self.args[1:] if not os.path.isdir(p) ] if len(files) < len(sys.argv[1:]): prints('Ignoring directories passed as command line arguments') if files: add_filesystem_book(files) for event in self.app.file_event_hook.events: add_filesystem_book(event) self.app.file_event_hook = add_filesystem_book def initialization_failed(self): print 'Catastrophic failure initializing GUI, bailing out...' QCoreApplication.exit(1) raise SystemExit(1) def initialize_db_stage2(self, db, tb): from calibre.db.legacy import LibraryDatabase if db is None and tb is not None: # DB Repair failed error_dialog(self.splash_screen, _('Repairing failed'), _('The database repair failed. Starting with ' 'a new empty library.'), det_msg=tb, show=True) if db is None: candidate = choose_dir( self.splash_screen, 'choose calibre library', _('Choose a location for your new calibre e-book library'), default_dir=get_default_library_path()) if not candidate: self.initialization_failed() try: self.library_path = candidate db = LibraryDatabase(candidate) except: error_dialog( self.splash_screen, _('Bad database location'), _('Bad database location %r. calibre will now quit.') % self.library_path, det_msg=traceback.format_exc(), show=True) self.initialization_failed() try: self.start_gui(db) except Exception: error_dialog( self.main, _('Startup error'), _('There was an error during {0} startup.' ' Parts of {0} may not function. Click Show details to learn more.' ).format(__appname__), det_msg=traceback.format_exc(), show=True) def initialize_db(self): from calibre.db.legacy import LibraryDatabase db = None try: db = LibraryDatabase(self.library_path) except apsw.Error: repair = question_dialog( self.splash_screen, _('Corrupted database'), _('The library database at %s appears to be corrupted. Do ' 'you want calibre to try and rebuild it automatically? ' 'The rebuild may not be completely successful. ' 'If you say No, a new empty calibre library will be created.' ) % force_unicode(self.library_path, filesystem_encoding), det_msg=traceback.format_exc()) if repair: if repair_library(self.library_path): db = LibraryDatabase(self.library_path) except: error_dialog(self.splash_screen, _('Bad database location'), _('Bad database location %r. Will start with ' ' a new, empty calibre library') % self.library_path, det_msg=traceback.format_exc(), show=True) self.initialize_db_stage2(db, None) def show_splash_screen(self): self.splash_pixmap = QPixmap() self.splash_pixmap.load(I('library.png')) self.splash_screen = QSplashScreen(self.splash_pixmap) self.splash_screen.showMessage( _('Starting %s: Loading books...') % __appname__) self.splash_screen.show() QApplication.instance().processEvents() def initialize(self, *args): if gprefs['show_splash_screen']: self.show_splash_screen() self.library_path = get_library_path(parent=self.splash_screen) if not self.library_path: self.initialization_failed() self.initialize_db()
class GuiRunner(QObject): '''Make sure an event loop is running before starting the main work of initialization''' def __init__(self, opts, args, actions, listener, app, gui_debug=None): self.startup_time = time.time() self.opts, self.args, self.listener, self.app = opts, args, listener, app self.gui_debug = gui_debug self.actions = actions self.main = None QObject.__init__(self) self.splash_screen = None self.timer = QTimer.singleShot(1, self.initialize) if DEBUG: prints('Starting up...') def start_gui(self, db): from calibre.gui2.ui import Main main = Main(self.opts, gui_debug=self.gui_debug) if self.splash_screen is not None: self.splash_screen.showMessage(_('Initializing user interface...')) with gprefs: # Only write gui.json after initialization is complete main.initialize(self.library_path, db, self.listener, self.actions) if self.splash_screen is not None: self.splash_screen.finish(main) if DEBUG: prints('Started up in %.2f seconds'%(time.time() - self.startup_time), 'with', len(db.data), 'books') add_filesystem_book = partial(main.iactions['Add Books'].add_filesystem_book, allow_device=False) sys.excepthook = main.unhandled_exception if len(self.args) > 1: files = [os.path.abspath(p) for p in self.args[1:] if not os.path.isdir(p)] if len(files) < len(sys.argv[1:]): prints('Ignoring directories passed as command line arguments') if files: add_filesystem_book(files) for event in self.app.file_event_hook.events: add_filesystem_book(event) self.app.file_event_hook = add_filesystem_book self.main = main def initialization_failed(self): print 'Catastrophic failure initializing GUI, bailing out...' QCoreApplication.exit(1) raise SystemExit(1) def initialize_db_stage2(self, db, tb): if db is None and tb is not None: # DB Repair failed error_dialog(self.splash_screen, _('Repairing failed'), _('The database repair failed. Starting with ' 'a new empty library.'), det_msg=tb, show=True) if db is None: candidate = choose_dir(self.splash_screen, 'choose calibre library', _('Choose a location for your new calibre e-book library'), default_dir=get_default_library_path()) if not candidate: self.initialization_failed() try: self.library_path = candidate db = self.db_class(candidate) except: error_dialog(self.splash_screen, _('Bad database location'), _('Bad database location %r. calibre will now quit.' )%self.library_path, det_msg=traceback.format_exc(), show=True) self.initialization_failed() self.start_gui(db) def initialize_db(self): from calibre.db import get_db_loader db = None self.db_class, errs = get_db_loader() try: db = self.db_class(self.library_path) except errs: repair = question_dialog(self.splash_screen, _('Corrupted database'), _('The library database at %s appears to be corrupted. Do ' 'you want calibre to try and rebuild it automatically? ' 'The rebuild may not be completely successful. ' 'If you say No, a new empty calibre library will be created.') % force_unicode(self.library_path, filesystem_encoding), det_msg=traceback.format_exc() ) if repair: if repair_library(self.library_path): db = self.db_class(self.library_path) except: error_dialog(self.splash_screen, _('Bad database location'), _('Bad database location %r. Will start with ' ' a new, empty calibre library')%self.library_path, det_msg=traceback.format_exc(), show=True) self.initialize_db_stage2(db, None) def show_splash_screen(self): self.splash_pixmap = QPixmap() self.splash_pixmap.load(I('library.png')) self.splash_screen = QSplashScreen(self.splash_pixmap) self.splash_screen.showMessage(_('Starting %s: Loading books...') % __appname__) self.splash_screen.show() QApplication.instance().processEvents() def initialize(self, *args): if gprefs['show_splash_screen']: self.show_splash_screen() self.library_path = get_library_path(parent=self.splash_screen) if not self.library_path: self.initialization_failed() self.initialize_db()
class LetsShareBooksDialog(QDialog): def __init__(self, gui, icon, do_user_config, qaction, us): QDialog.__init__(self, gui) self.gui = gui self.do_user_config = do_user_config self.qaction = qaction self.us = us self.clip = QApplication.clipboard() self.main_gui = calibre_main() self.urllib_thread = UrlLibThread(self.us) self.kill_servers_thread = KillServersThread(self.us) self.us.check_finished = True self.pxmp = QPixmap() self.pxmp.load('images/icon_connected.png') self.icon_connected = QIcon(self.pxmp) self.setStyleSheet(""" QDialog { background-color: white; } QPushButton { font-size: 16px; border-style: solid; border-color: red; font-family:'BitstreamVeraSansMono',Consolas,monospace; text-transform: uppercase; } QPushButton#arrow { border-width: 16px; border-right-color:white; padding: -10px; color:red; } QPushButton#url { background-color: red; min-width: 460px; color: white; text-align: left; } QPushButton#url:hover { background-color: white; color: red; } QPushButton#share { background-color: red; color: white; margin-right: 10px; } QPushButton#share:hover { background-color: white; color: red; } QPushButton#url2 { color: #222; text-align: left; } QPushButton#url2:hover { color: red; } """) self.ll = QVBoxLayout() #self.ll.setSpacing(1) self.l = QHBoxLayout() self.l.setSpacing(0) self.l.setMargin(0) #self.l.setContentsMargins(0,0,0,0) self.w = QWidget() self.w.setLayout(self.l) self.setLayout(self.ll) self.setWindowIcon(icon) self.lets_share_button = QPushButton() self.lets_share_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.lets_share_button.setObjectName("share") self.lets_share_button.clicked.connect(self.lets_share) self.stop_share_button = QPushButton() self.stop_share_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.stop_share_button.setObjectName("share") self.stop_share_button.clicked.connect(self.stop_share) self.l.addWidget(self.lets_share_button) self.l.addWidget(self.stop_share_button) if self.us.button_state == "start": self.lets_share_button.show() self.stop_share_button.hide() self.lets_share_button.setText(self.us.share_button_text) else: self.lets_share_button.hide() self.stop_share_button.show() self.stop_share_button.setText(self.us.share_button_text) self.url_label = QPushButton() self.url_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.url_label.setObjectName("url") self.url_label.clicked.connect(self.open_url) self.l.addWidget(self.url_label) self.arrow_button = QPushButton("_____") self.arrow_button.setObjectName("arrow") self.l.addWidget(self.arrow_button) self.ll.addWidget(self.w) self.ll.addSpacing(10) self.chat_button = QPushButton("Chat room: https://chat.memoryoftheworld.org") #self.chat_button.hovered.connect(self.setCursorToHand) self.chat_button.setObjectName("url2") self.chat_button.setToolTip('Meetings every thursday at 23:59 (central eruopean time)') self.chat_button.clicked.connect(functools.partial(self.open_url2, "https://chat.memoryoftheworld.org")) self.ll.addWidget(self.chat_button) self.about_project_button = QPushButton('Public Library: http://www.memoryoftheworld.org') self.about_project_button.setObjectName("url2") self.about_project_button.setToolTip('When everyone is librarian, library is everywhere.') self.about_project_button.clicked.connect(functools.partial(self.open_url2, "http://www.memoryoftheworld.org")) self.ll.addWidget(self.about_project_button) self.debug_log = QListWidget() self.ll.addWidget(self.debug_log) self.debug_log.addItem("Initiatied!") self.metadata_thread = MetadataLibThread(self.debug_log) self.metadata_button = QPushButton("Get library metadata!") self.metadata_button.setObjectName("url2") self.metadata_button.setToolTip('Get library metadata!') self.metadata_button.clicked.connect(self.get_metadata) self.ll.addWidget(self.metadata_button) self.upgrade_button = QPushButton('Please download and upgrade from {0} to {1} version of plugin.'.format(self.us.running_version, self.us.latest_version)) self.upgrade_button.setObjectName("url2") self.upgrade_button.setToolTip('Running latest version you make developers happy') self.upgrade_button.clicked.connect(functools.partial(self.open_url2, self.us.plugin_url)) version_list = [self.us.running_version, self.us.latest_version] version_list.sort(key=lambda s: map(int, s.split('.'))) if self.us.running_version != self.us.latest_version: if self.us.running_version == version_list[0]: self.ll.addSpacing(20) self.ll.addWidget(self.upgrade_button) self.resize(self.sizeHint()) self.se = open("lsb.log", "w+b") self.so = self.se sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) os.dup2(self.so.fileno(), sys.stdout.fileno()) os.dup2(self.se.fileno(), sys.stderr.fileno()) self.timer = QTimer() self.timer.timeout.connect(self.check_and_render) self.timer_period = 300 self.timer.start(self.timer_period) self.error_log = "" def lets_share(self): self.lets_share_button.setEnabled(False) self.timer.stop() self.us.share_button_text = "Connecting..." #self.debug_log.addItem("Let's share!") self.us.counter = 0 self.us.lost_connection = False if not self.us.ssh_proc: self.main_gui.start_content_server() opts, args = server_config().option_parser().parse_args(['calibre-server']) self.calibre_server_port = opts.port if sys.platform == "win32": self.win_reg = subprocess.Popen("regedit /s .hosts.reg") self.us.win_port = int(random.random()*40000+10000) self.us.ssh_proc = subprocess.Popen("lsbtunnel.exe -N -T tunnel@{2} -R {0}:localhost:{1} -P 722".format(self.us.win_port, self.calibre_server_port, prefs['lsb_server']), shell=True) self.us.lsb_url = "https://www{0}.{1}".format(self.us.win_port, prefs['lsb_server']) #_dev_self.us.lsb_url = "http://www{0}.{1}".format(self.us.win_port, prefs['lsb_server']) self.us.lsb_url_text = "Go to: {0}".format(self.us.lsb_url) self.us.found_url = True else: self.us.ssh_proc = subprocess.Popen(['ssh', '-T', '-N', '-g', '-o', 'UserKnownHostsFile=.userknownhostsfile', '-o', 'TCPKeepAlive=yes', '-o', 'ServerAliveINterval=60', prefs['lsb_server'], '-l', 'tunnel', '-R', '0:localhost:{0}'.format(self.calibre_server_port), '-p', '722']) self.us.found_url = None self.qaction.setIcon(get_icon('images/icon_connected.png')) self.us.connecting = True self.us.connecting_now = datetime.datetime.now() self.timer.start(self.timer_period) def stop_share(self): self.stop_share_button.setEnabled(False) #self.debug_log.addItem("Stop Share!") self.timer.stop() self.us.lsb_url = 'nourl' self.us.urllib_result = '' self.us.disconnecting = True self.qaction.setIcon(get_icon('images/icon.png')) self.kill_servers_thread.start() self.timer.start(self.timer_period) def check_and_render(self): #self.show_debug() if self.us.button_state == "start": self.stop_share_button.hide() self.lets_share_button.show() self.lets_share_button.setText(self.us.share_button_text) else: self.lets_share_button.hide() self.stop_share_button.show() self.stop_share_button.setText(self.us.share_button_text) if self.us.disconnecting: self.us.share_button_text = "Disconnecting..." if self.us.lost_connection: self.us.lsb_url_text = 'Lost connection. Please start sharing again.' self.us.url_label_tooltip = '<<<< Click on Start sharing button again.' else: self.us.lsb_url_text = 'Be a librarian. Share your library.' self.us.url_label_tooltip = '<<<< Be a librarian. Click on Start sharing button.<<<<' if self.us.kill_finished: #self.debug_log.addItem("Let's share connect!") self.us.button_state = "start" self.us.share_button_text = "Start sharing" self.us.disconnecting = False self.us.kill_finished = False self.lets_share_button.setEnabled(True) elif self.us.connecting: if self.us.connecting_now: if (datetime.datetime.now() - self.us.connecting_now) > datetime.timedelta(seconds=10): #self.debug_log.addItem("Timeout!") self.us.http_error = None self.us.lost_connection = True self.us.connecting = False self.us.connecting_now = None self.stop_share() elif self.us.found_url: self.us.check_finished = False self.urllib_thread.start() if self.us.lsb_url == "nourl" and self.us.ssh_proc and sys.platform != "win32": #self.debug_log.addItem("Wait for Allocated port!") self.se.seek(0) result = self.se.readlines() for line in result: m = re.match("^Allocated port (.*) for .*", line) try: #self.debug_log.addItem(self.us.lsb_url) self.us.lsb_url = 'https://www{0}.{1}'.format(m.groups()[0], prefs['lsb_server']) #_dev_self.us.lsb_url = 'http://www{0}.{1}'.format(m.groups()[0], prefs['lsb_server']) self.us.lsb_url_text = "Go to: {0}".format(self.us.lsb_url) self.us.url_label_tooltip = 'Copy URL to clipboard and check it out in a browser!' self.us.http_error = None self.us.found_url = True except: pass elif self.us.urllib_result == 200: #self.debug_log.addItem("Finish Connecting State!") self.se.seek(0) self.se.truncate() self.us.share_button_text = "Stop sharing" self.us.button_state = "stop" self.stop_share_button.setEnabled(True) self.us.connecting = False self.us.connecting_now = None self.us.found_url = None elif self.us.http_error and self.us.button_state == "stop": #self.debug_log.addItem("Error!") self.us.http_error = None self.us.lost_connection = True self.stop_share() elif self.us.check_finished: #if self.debug_log.item(self.debug_log.count()-1).text()[:10] == "Finally Ca": # self.us.debug_counter = self.us.debug_counter + 1 #else: # self.debug_log.addItem("Finally Called Thread!({0})".format(self.us.debug_counter)) # self.us.debug_counter = 1 self.us.check_finished = False self.urllib_thread.start() if self.us.urllib_result == 200 and self.us.button_state == "stop": self.stop_share_button.setEnabled(True) if self.us.lsb_url == 'nourl' and self.us.button_state == "start": self.lets_share_button.setEnabled(True) self.setWindowTitle("{0} - {1}".format(self.us.window_title, self.us.lsb_url)) self.url_label.setToolTip(self.us.url_label_tooltip) self.url_label.setText(self.us.lsb_url_text) def open_url(self): if self.us.lsb_url == "nourl" and not self.us.http_error: self.us.url_label_tooltip = '<<<< Be a librarian. Click on Start sharing button.' self.us.lsb_url_text = '<<<< Be a librarian. Click on Start sharing button.' else: self.clip.setText(self.us.lsb_url) webbrowser.open(str(self.us.lsb_url)) if self.us.lsb_url != "nourl": self.us.lsb_url_text = "Library at: {0}".format(self.us.lsb_url) def open_url2(self, url): self.clip.setText(url) webbrowser.open(url) def get_metadata(self): self.metadata_thread.start() def show_debug(self): if self.us.debug_item: self.debug_log.addItem(str(self.us.debug_item)) self.us.debug_item = None self.debug_log.scrollToBottom() self.debug_log.repaint() def closeEvent(self, e): self.hide() #self.urllib_thread.stop() #self.kill_servers_thread.stop() def config(self): self.do_user_config(parent=self) self.label.setText(prefs['lsb_server'])
def _fetch_marvin_cover(with_border=False): ''' Retrieve LargeCoverJpg from cache ''' self._log_location() con = sqlite3.connect(self.marvin_db_path) with con: con.row_factory = sqlite3.Row # Fetch Hash from mainDb cover_cur = con.cursor() cover_cur.execute('''SELECT Hash FROM Books WHERE ID = '{0}' '''.format(self.book_id)) row = cover_cur.fetchone() book_hash = row[b'Hash'] large_covers_subpath = self.connected_device._cover_subpath( size="large") cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash]) stats = self.parent.ios.exists(cover_path) if stats: self._log("fetching large cover from cache") #self._log("cover size: {:,} bytes".format(int(stats['st_size']))) cover_bytes = self.parent.ios.read(cover_path, mode='rb') m_image = QImage() m_image.loadFromData(cover_bytes) if with_border: m_image = m_image.scaledToHeight( self.COVER_ICON_SIZE - self.BORDER_WIDTH * 2, Qt.SmoothTransformation) # Construct a QPixmap with yellow background self.m_pixmap = QPixmap( QSize(m_image.width() + self.BORDER_WIDTH * 2, m_image.height() + self.BORDER_WIDTH * 2)) m_painter = QPainter(self.m_pixmap) m_painter.setRenderHints(m_painter.Antialiasing) m_painter.fillRect(self.m_pixmap.rect(), QColor(0xFD, 0xFF, 0x99)) m_painter.drawImage(self.BORDER_WIDTH, self.BORDER_WIDTH, m_image) else: m_image = m_image.scaledToHeight(self.COVER_ICON_SIZE, Qt.SmoothTransformation) self.m_pixmap = QPixmap( QSize(m_image.width(), m_image.height())) m_painter = QPainter(self.m_pixmap) m_painter.setRenderHints(m_painter.Antialiasing) m_painter.drawImage(0, 0, m_image) self.marvin_cover.setPixmap(self.m_pixmap) else: # No cover available, use generic self._log("No cached cover, using generic") pixmap = QPixmap() pixmap.load(I('book.png')) pixmap = pixmap.scaled(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE, aspectRatioMode=Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) self.marvin_cover.setPixmap(pixmap)
class ImagePopup(object): def __init__(self, parent): self.current_img = QPixmap() self.current_url = QUrl() self.parent = parent self.dialogs = [] def __call__(self): if self.current_img.isNull(): return d = ImageView(self.parent, self.current_img, self.current_url) self.dialogs.append(d) d.finished.connect(self.cleanup, type=Qt.QueuedConnection) d() def cleanup(self): for d in tuple(self.dialogs): if not d.isVisible(): self.dialogs.remove(d) if __name__ == '__main__': import sys app = QApplication([]) p = QPixmap() p.load(sys.argv[-1]) u = QUrl.fromLocalFile(sys.argv[-1]) d = ImageView(None, p, u) d() app.exec_()
class LetsShareBooksDialog(QDialog): def __init__(self, gui, icon, do_user_config, qaction, us): QDialog.__init__(self, gui) self.gui = gui self.do_user_config = do_user_config self.qaction = qaction self.us = us self.clip = QApplication.clipboard() self.main_gui = calibre_main() self.urllib_thread = UrlLibThread(self.us) self.kill_servers_thread = KillServersThread(self.us) self.us.check_finished = True self.pxmp = QPixmap() self.pxmp.load('images/icon_connected.png') self.icon_connected = QIcon(self.pxmp) self.setStyleSheet(""" QDialog { background-color: white; } QPushButton { font-size: 16px; border-style: solid; border-color: red; font-family:'BitstreamVeraSansMono',Consolas,monospace; text-transform: uppercase; } QPushButton#arrow { border-width: 16px; border-right-color:white; padding: -10px; color:red; } QPushButton#url { background-color: red; min-width: 460px; color: white; text-align: left; } QPushButton#url:hover { background-color: white; color: red; } QPushButton#share { background-color: red; color: white; margin-right: 10px; } QPushButton#share:hover { background-color: white; color: red; } QPushButton#url2 { color: #222; text-align: left; } QPushButton#url2:hover { color: red; } """) self.ll = QVBoxLayout() #self.ll.setSpacing(1) self.l = QHBoxLayout() self.l.setSpacing(0) self.l.setMargin(0) #self.l.setContentsMargins(0,0,0,0) self.w = QWidget() self.w.setLayout(self.l) self.setLayout(self.ll) self.setWindowIcon(icon) self.lets_share_button = QPushButton() self.lets_share_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.lets_share_button.setObjectName("share") self.lets_share_button.clicked.connect(self.lets_share) self.stop_share_button = QPushButton() self.stop_share_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.stop_share_button.setObjectName("share") self.stop_share_button.clicked.connect(self.stop_share) self.l.addWidget(self.lets_share_button) self.l.addWidget(self.stop_share_button) if self.us.button_state == "start": self.lets_share_button.show() self.stop_share_button.hide() self.lets_share_button.setText(self.us.share_button_text) else: self.lets_share_button.hide() self.stop_share_button.show() self.stop_share_button.setText(self.us.share_button_text) self.url_label = QPushButton() self.url_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.url_label.setObjectName("url") self.url_label.clicked.connect(self.open_url) self.l.addWidget(self.url_label) self.arrow_button = QPushButton("_____") self.arrow_button.setObjectName("arrow") self.l.addWidget(self.arrow_button) self.ll.addWidget(self.w) self.ll.addSpacing(10) self.chat_button = QPushButton("Chat room: https://chat.memoryoftheworld.org") #self.chat_button.hovered.connect(self.setCursorToHand) self.chat_button.setObjectName("url2") self.chat_button.setToolTip('Meetings every thursday at 23:59 (central eruopean time)') self.chat_button.clicked.connect(functools.partial(self.open_url2, "https://chat.memoryoftheworld.org")) self.ll.addWidget(self.chat_button) self.about_project_button = QPushButton('Public Library: http://www.memoryoftheworld.org') self.about_project_button.setObjectName("url2") self.about_project_button.setToolTip('When everyone is librarian, library is everywhere.') self.about_project_button.clicked.connect(functools.partial(self.open_url2, "http://www.memoryoftheworld.org")) self.ll.addWidget(self.about_project_button) #self.debug_log = QListWidget() #self.ll.addWidget(self.debug_log) #self.debug_log.addItem("Initiatied!") self.upgrade_button = QPushButton('Please download and upgrade from {0} to {1} version of plugin.'.format(self.us.running_version, self.us.latest_version)) self.upgrade_button.setObjectName("url2") self.upgrade_button.setToolTip('Running latest version you make developers happy') self.upgrade_button.clicked.connect(functools.partial(self.open_url2, self.us.plugin_url)) version_list = [self.us.running_version, self.us.latest_version] version_list.sort(key=lambda s: map(int, s.split('.'))) if self.us.running_version != self.us.latest_version: if self.us.running_version == version_list[0]: self.ll.addSpacing(20) self.ll.addWidget(self.upgrade_button) self.resize(self.sizeHint()) self.se = open("lsb.log", "w+b") self.so = self.se sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) os.dup2(self.so.fileno(), sys.stdout.fileno()) os.dup2(self.se.fileno(), sys.stderr.fileno()) self.timer = QTimer() self.timer.timeout.connect(self.check_and_render) self.timer_period = 300 self.timer.start(self.timer_period) self.error_log = "" def lets_share(self): self.lets_share_button.setEnabled(False) self.timer.stop() self.us.share_button_text = "Connecting..." #self.debug_log.addItem("Let's share!") self.us.counter = 0 self.us.lost_connection = False if not self.us.ssh_proc: self.main_gui.start_content_server() opts, args = server_config().option_parser().parse_args(['calibre-server']) self.calibre_server_port = opts.port if sys.platform == "win32": self.win_reg = subprocess.Popen("regedit /s .hosts.reg") self.us.win_port = int(random.random()*40000+10000) self.us.ssh_proc = subprocess.Popen("lsbtunnel.exe -N -T tunnel@{2} -R {0}:localhost:{1} -P 722".format(self.us.win_port, self.calibre_server_port, prefs['lsb_server']), shell=True) self.us.lsb_url = "https://www{0}.{1}".format(self.us.win_port, prefs['lsb_server']) #_dev_self.us.lsb_url = "http://www{0}.{1}".format(self.us.win_port, prefs['lsb_server']) self.us.lsb_url_text = "Go to: {0}".format(self.us.lsb_url) self.us.found_url = True else: self.us.ssh_proc = subprocess.Popen(['ssh', '-T', '-N', '-g', '-o', 'UserKnownHostsFile=.userknownhostsfile', '-o', 'TCPKeepAlive=yes', '-o', 'ServerAliveINterval=60', prefs['lsb_server'], '-l', 'tunnel', '-R', '0:localhost:{0}'.format(self.calibre_server_port), '-p', '722']) self.us.found_url = None self.qaction.setIcon(get_icon('images/icon_connected.png')) self.us.connecting = True self.us.connecting_now = datetime.datetime.now() self.timer.start(self.timer_period) def stop_share(self): self.stop_share_button.setEnabled(False) #self.debug_log.addItem("Stop Share!") self.timer.stop() self.us.lsb_url = 'nourl' self.us.urllib_result = '' self.us.disconnecting = True self.qaction.setIcon(get_icon('images/icon.png')) self.kill_servers_thread.start() self.timer.start(self.timer_period) def check_and_render(self): #self.show_debug() if self.us.button_state == "start": self.stop_share_button.hide() self.lets_share_button.show() self.lets_share_button.setText(self.us.share_button_text) else: self.lets_share_button.hide() self.stop_share_button.show() self.stop_share_button.setText(self.us.share_button_text) if self.us.disconnecting: self.us.share_button_text = "Disconnecting..." if self.us.lost_connection: self.us.lsb_url_text = 'Lost connection. Please start sharing again.' self.us.url_label_tooltip = '<<<< Click on Start sharing button again.' else: self.us.lsb_url_text = 'Be a librarian. Share your library.' self.us.url_label_tooltip = '<<<< Be a librarian. Click on Start sharing button.<<<<' if self.us.kill_finished: #self.debug_log.addItem("Let's share connect!") self.us.button_state = "start" self.us.share_button_text = "Start sharing" self.us.disconnecting = False self.us.kill_finished = False self.lets_share_button.setEnabled(True) elif self.us.connecting: if self.us.connecting_now: if (datetime.datetime.now() - self.us.connecting_now) > datetime.timedelta(seconds=10): #self.debug_log.addItem("Timeout!") self.us.http_error = None self.us.lost_connection = True self.us.connecting = False self.us.connecting_now = None self.stop_share() elif self.us.found_url: self.us.check_finished = False self.urllib_thread.start() if self.us.lsb_url == "nourl" and self.us.ssh_proc and sys.platform != "win32": #self.debug_log.addItem("Wait for Allocated port!") self.se.seek(0) result = self.se.readlines() for line in result: m = re.match("^Allocated port (.*) for .*", line) try: #self.debug_log.addItem(self.us.lsb_url) self.us.lsb_url = 'https://www{0}.{1}'.format(m.groups()[0], prefs['lsb_server']) #_dev_self.us.lsb_url = 'http://www{0}.{1}'.format(m.groups()[0], prefs['lsb_server']) self.us.lsb_url_text = "Go to: {0}".format(self.us.lsb_url) self.us.url_label_tooltip = 'Copy URL to clipboard and check it out in a browser!' self.us.http_error = None self.us.found_url = True except: pass elif self.us.urllib_result == 200: #self.debug_log.addItem("Finish Connecting State!") self.se.seek(0) self.se.truncate() self.us.share_button_text = "Stop sharing" self.us.button_state = "stop" self.stop_share_button.setEnabled(True) self.us.connecting = False self.us.connecting_now = None self.us.found_url = None elif self.us.http_error and self.us.button_state == "stop": #self.debug_log.addItem("Error!") self.us.http_error = None self.us.lost_connection = True self.stop_share() elif self.us.check_finished: #if self.debug_log.item(self.debug_log.count()-1).text()[:10] == "Finally Ca": # self.us.debug_counter = self.us.debug_counter + 1 #else: # self.debug_log.addItem("Finally Called Thread!({0})".format(self.us.debug_counter)) # self.us.debug_counter = 1 self.us.check_finished = False self.urllib_thread.start() if self.us.urllib_result == 200 and self.us.button_state == "stop": self.stop_share_button.setEnabled(True) if self.us.lsb_url == 'nourl' and self.us.button_state == "start": self.lets_share_button.setEnabled(True) self.setWindowTitle("{0} - {1}".format(self.us.window_title, self.us.lsb_url)) self.url_label.setToolTip(self.us.url_label_tooltip) self.url_label.setText(self.us.lsb_url_text) def open_url(self): if self.us.lsb_url == "nourl" and not self.us.http_error: self.us.url_label_tooltip = '<<<< Be a librarian. Click on Start sharing button.' self.us.lsb_url_text = '<<<< Be a librarian. Click on Start sharing button.' else: self.clip.setText(self.us.lsb_url) webbrowser.open(str(self.us.lsb_url)) if self.us.lsb_url != "nourl": self.us.lsb_url_text = "Library at: {0}".format(self.us.lsb_url) def open_url2(self, url): self.clip.setText(url) webbrowser.open(url) def show_debug(self): if self.us.debug_item: self.debug_log.addItem(str(self.us.debug_item)) self.us.debug_item = None self.debug_log.scrollToBottom() self.debug_log.repaint() def closeEvent(self, e): self.hide() #self.urllib_thread.stop() #self.kill_servers_thread.stop() def config(self): self.do_user_config(parent=self) self.label.setText(prefs['lsb_server'])
class GuiRunner(QObject): """Make sure an event loop is running before starting the main work of initialization""" def __init__(self, opts, args, actions, listener, app, gui_debug=None): self.startup_time = time.time() self.opts, self.args, self.listener, self.app = opts, args, listener, app self.gui_debug = gui_debug self.actions = actions self.main = None QObject.__init__(self) self.splash_screen = None self.timer = QTimer.singleShot(1, self.initialize) if DEBUG: prints("Starting up...") def start_gui(self, db): from calibre.gui2.ui import Main main = self.main = Main(self.opts, gui_debug=self.gui_debug) if self.splash_screen is not None: self.splash_screen.showMessage(_("Initializing user interface...")) with gprefs: # Only write gui.json after initialization is complete main.initialize(self.library_path, db, self.listener, self.actions) if self.splash_screen is not None: self.splash_screen.finish(main) if DEBUG: prints("Started up in %.2f seconds" % (time.time() - self.startup_time), "with", len(db.data), "books") add_filesystem_book = partial(main.iactions["Add Books"].add_filesystem_book, allow_device=False) sys.excepthook = main.unhandled_exception if len(self.args) > 1: files = [os.path.abspath(p) for p in self.args[1:] if not os.path.isdir(p)] if len(files) < len(sys.argv[1:]): prints("Ignoring directories passed as command line arguments") if files: add_filesystem_book(files) for event in self.app.file_event_hook.events: add_filesystem_book(event) self.app.file_event_hook = add_filesystem_book def initialization_failed(self): print "Catastrophic failure initializing GUI, bailing out..." QCoreApplication.exit(1) raise SystemExit(1) def initialize_db_stage2(self, db, tb): from calibre.db.legacy import LibraryDatabase if db is None and tb is not None: # DB Repair failed error_dialog( self.splash_screen, _("Repairing failed"), _("The database repair failed. Starting with " "a new empty library."), det_msg=tb, show=True, ) if db is None: candidate = choose_dir( self.splash_screen, "choose calibre library", _("Choose a location for your new calibre e-book library"), default_dir=get_default_library_path(), ) if not candidate: self.initialization_failed() try: self.library_path = candidate db = LibraryDatabase(candidate) except: error_dialog( self.splash_screen, _("Bad database location"), _("Bad database location %r. calibre will now quit.") % self.library_path, det_msg=traceback.format_exc(), show=True, ) self.initialization_failed() try: self.start_gui(db) except Exception: error_dialog( self.main, _("Startup error"), _( "There was an error during {0} startup." " Parts of {0} may not function. Click Show details to learn more." ).format(__appname__), det_msg=traceback.format_exc(), show=True, ) def initialize_db(self): from calibre.db.legacy import LibraryDatabase db = None try: db = LibraryDatabase(self.library_path) except apsw.Error: repair = question_dialog( self.splash_screen, _("Corrupted database"), _( "The library database at %s appears to be corrupted. Do " "you want calibre to try and rebuild it automatically? " "The rebuild may not be completely successful. " "If you say No, a new empty calibre library will be created." ) % force_unicode(self.library_path, filesystem_encoding), det_msg=traceback.format_exc(), ) if repair: if repair_library(self.library_path): db = LibraryDatabase(self.library_path) except: error_dialog( self.splash_screen, _("Bad database location"), _("Bad database location %r. Will start with " " a new, empty calibre library") % self.library_path, det_msg=traceback.format_exc(), show=True, ) self.initialize_db_stage2(db, None) def show_splash_screen(self): self.splash_pixmap = QPixmap() self.splash_pixmap.load(I("library.png")) self.splash_screen = QSplashScreen(self.splash_pixmap) self.splash_screen.showMessage(_("Starting %s: Loading books...") % __appname__) self.splash_screen.show() QApplication.instance().processEvents() def initialize(self, *args): if gprefs["show_splash_screen"]: self.show_splash_screen() self.library_path = get_library_path(parent=self.splash_screen) if not self.library_path: self.initialization_failed() self.initialize_db()