From 2646a40edb1d9b5b38928975ddf900b82e3f8273 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Wed, 11 Mar 2009 05:19:02 +0900 Subject: [PATCH] deck and plugin sharing --- ankiqt/ui/__init__.py | 1 + ankiqt/ui/exporting.py | 17 +++- ankiqt/ui/getshared.py | 210 +++++++++++++++++++++++++++++++++++++++ ankiqt/ui/main.py | 216 +++++++++++++++++++++++++---------------- ankiqt/ui/view.py | 15 +-- designer/exporting.ui | 13 +++ designer/getshared.ui | 121 +++++++++++++++++++++++ designer/main.ui | 63 ++++++++---- designer/share.ui | 134 +++++++++++++++++++++++++ 9 files changed, 671 insertions(+), 119 deletions(-) create mode 100644 ankiqt/ui/getshared.py create mode 100644 designer/getshared.ui create mode 100644 designer/share.ui diff --git a/ankiqt/ui/__init__.py b/ankiqt/ui/__init__.py index 585f049e5..aa1c82e65 100644 --- a/ankiqt/ui/__init__.py +++ b/ankiqt/ui/__init__.py @@ -26,6 +26,7 @@ def importAll(): import update import utils import view + import getshared class DialogManager(object): diff --git a/ankiqt/ui/exporting.py b/ankiqt/ui/exporting.py index 873bda842..c01430a85 100644 --- a/ankiqt/ui/exporting.py +++ b/ankiqt/ui/exporting.py @@ -4,10 +4,20 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import anki, ankiqt -from anki.exporting import exporters +from anki.exporting import exporters as exporters_ from anki.utils import parseTags from ankiqt import ui +class PackagedAnkiExporter(object): + def __init__(self, *args): + pass + +def exporters(): + l = list(exporters_()) + l.insert(1, (_("Packaged Anki Deck (*.zip)"), + PackagedAnkiExporter)) + return l + class ExportDialog(QDialog): def __init__(self, parent): @@ -35,7 +45,7 @@ class ExportDialog(QDialog): self.setTabOrder(self.tags, self.dialog.includeScheduling) # save button - b = QPushButton(_("Export to...")) + b = QPushButton(_("Export...")) self.dialog.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) def exporterChanged(self, idx): @@ -50,6 +60,9 @@ class ExportDialog(QDialog): self.dialog.includeTags.hide() def accept(self): + if isinstance(self.exporter, PackagedAnkiExporter): + self.parent.onShare(parseTags(unicode(self.tags.text()))) + return QDialog.accept(self) file = ui.utils.getSaveFile(self, _("Choose file to export to"), "export", self.exporter.key, self.exporter.ext) self.hide() diff --git a/ankiqt/ui/getshared.py b/ankiqt/ui/getshared.py new file mode 100644 index 000000000..3fc3b2fb7 --- /dev/null +++ b/ankiqt/ui/getshared.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- +# Copyright: Damien Elmes +# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html + +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.QtNetwork import * +import ankiqt, simplejson, time, cStringIO, zipfile, tempfile, os, re +from ankiqt.ui.utils import saveGeom, restoreGeom, showInfo +from anki.utils import fmtTimeSpan + +R_ID = 0 +R_USERNAME = 1 +R_TITLE = 2 +R_DESCRIPTION = 3 +R_TAGS = 4 +R_VERSION = 5 +R_FACTS = 6 +R_SIZE = 7 +R_COUNT = 8 +R_MODIFIED = 9 +R_FNAME = 10 + +class GetShared(QDialog): + + def __init__(self, parent, type): + QDialog.__init__(self, parent, Qt.Window) + self.parent = parent + self.form = ankiqt.forms.getshared.Ui_Dialog() + self.form.setupUi(self) + restoreGeom(self, "getshared") + self.setupTable() + self.onChangeType(type) + self.ok = False + if type == 0: + self.setWindowTitle(_("Download Shared Deck")) + else: + self.setWindowTitle(_("Download Shared Plugin")) + self.exec_() + + def setupTable(self): + self.connect( + self.form.table, SIGNAL("currentCellChanged(int,int,int,int)"), + self.onCellChanged) + self.form.table.verticalHeader().setDefaultSectionSize( + self.parent.config['editLineSize']) + self.form.search.setText("search not yet implemented") + + def fetchData(self): + h = QHttp(self) + h.connect(h, SIGNAL("requestFinished(int,bool)"), self.onReqFin) + h.setHost("anki.ichi2.net") + #h.setHost("localhost", 8001) + self.conId = h.get("/file/search?t=%d" % self.type) + self.http = h + self.parent.setProgressParent(self) + self.parent.startProgress() + + def onReqFin(self, id, err): + "List fetched." + if id != self.conId: + return + self.parent.finishProgress() + self.parent.setProgressParent(None) + if err: + showInfo(_("Unable to connect to server."), parent=self) + self.close() + return + data = self.http.readAll() + self.allList = simplejson.loads(unicode(data)) + self.typeChanged() + self.limit() + + def limit(self): + self.curList = self.allList + self.redraw() + + def redraw(self): + self.form.table.setSortingEnabled(False) + self.form.table.setRowCount(len(self.curList)) + self.items = {} + if self.type == 0: + cols = (R_TITLE, R_FACTS, R_MODIFIED) + else: + cols = (R_TITLE, R_MODIFIED) + for rc, r in enumerate(self.curList): + for cc, c in enumerate(cols): + if c == R_MODIFIED: + txt = time.strftime("%m/%Y", time.localtime(r[c])) + else: + txt = unicode(r[c]) + item = QTableWidgetItem(txt) + self.items[item] = r + self.form.table.setItem(rc, cc, item) + self.form.table.setSortingEnabled(True) + self.form.table.selectRow(0) + + def onCellChanged(self, row, col, x, y): + ci = self.form.table.currentItem() + if not ci: + self.form.bottomLabel.setText(_("Nothing selected.")) + return + r = self.items[ci] + self.curRow = r + self.form.bottomLabel.setText(_("""\ +Title: %(title)s
+Tags: %(tags)s
+Size: %(size)0.2fKB
+Uploader: %(author)s
+Downloads: %(count)s
+Description:
%(description)s""") % { + 'title': r[R_TITLE], + 'tags': r[R_TAGS], + 'size': r[R_SIZE] / 1024.0, + 'author': r[R_USERNAME], + 'count': r[R_COUNT], + 'description': r[R_DESCRIPTION].replace("\n", "
"), + }) + self.form.scrollAreaWidgetContents.adjustSize() + self.form.scrollArea.setWidget(self.form.scrollAreaWidgetContents) + + def onChangeType(self, type): + self.type = type + self.fetchData() + + def typeChanged(self): + self.form.table.clear() + if self.type == 0: + self.form.table.setColumnCount(3) + self.form.table.setHorizontalHeaderLabels([ + _("Title"), _("Facts"), _("Modified")]) + else: + self.form.table.setColumnCount(2) + self.form.table.setHorizontalHeaderLabels([ + _("Title"), _("Modified")]) + self.form.table.horizontalHeader().setResizeMode( + 0, QHeaderView.Stretch) + self.form.table.verticalHeader().hide() + self.form.table.setSelectionBehavior(QAbstractItemView.SelectRows) + + def accept(self): + h = QHttp(self) + h.connect(h, SIGNAL("requestFinished(int,bool)"), self.onReqFin2) + h.setHost("anki.ichi2.net") + #h.setHost("localhost", 8001) + self.conId = h.get("/file/get?id=%d" % self.curRow[R_ID]) + self.http = h + self.parent.setProgressParent(self) + self.parent.startProgress() + + def onReqFin2(self, id, err): + "File fetched." + if id != self.conId: + return + try: + self.parent.finishProgress() + self.parent.setProgressParent(None) + if err: + showInfo(_("Unable to connect to server."), parent=self) + self.close() + return + data = self.http.readAll() + ext = os.path.splitext(self.curRow[R_FNAME])[1] + if ext == ".zip": + f = cStringIO.StringIO() + f.write(data) + z = zipfile.ZipFile(f) + else: + z = None + tit = self.curRow[R_TITLE] + tit = re.sub("[^][A-Za-z0-9 ()\-]", "", tit) + tit = tit[0:40] + if self.type == 0: + # deck + dd = self.parent.documentDir + p = os.path.join(dd, tit + ".anki") + if os.path.exists(p): + tit += "%d" % time.time() + for l in z.namelist(): + if l == "shared.anki": + dpath = os.path.join(dd, tit + ".anki") + open(dpath, "w").write(z.read(l)) + elif l.startswith("shared.media/"): + try: + os.mkdir(os.path.join(dd, tit + ".media")) + except OSError: + pass + open(os.path.join(dd, tit + ".media", + os.path.basename(l)),"w").write(z.read(l)) + self.parent.loadDeck(dpath) + self.ok = True + else: + pd = self.parent.pluginsFolder() + if z: + raise "nyi" +# for l in z.namelist(): +# try: +# os.mkdir(os.path.join(pd, os.path.dirname(l))) +# except OSError: +# pass +# open(os.path.join(pd, 2)) + else: + open(os.path.join(pd, tit + ext), "w").write(data) + showInfo(_("Plugin downloaded. Please restart Anki."), + parent=self) + self.ok = True + return + finally: + QDialog.accept(self) + diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index d3ab36075..39f542d06 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -6,8 +6,8 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * from PyQt4.QtWebKit import QWebPage -import os, sys, re, types, gettext, stat, traceback -import shutil, time, glob, tempfile, datetime +import os, sys, re, types, gettext, stat, traceback, inspect +import shutil, time, glob, tempfile, datetime, zipfile from PyQt4.QtCore import * from PyQt4.QtGui import * @@ -627,50 +627,10 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) latest = self.config['recentDeckPaths'][0] defaultDir = os.path.dirname(latest) else: - if save: - defaultDir = unicode(os.path.expanduser("~/"), - sys.getfilesystemencoding()) - else: - samples = self.getSamplesDir() - if samples: - return samples + defaultDir = unicode(os.path.expanduser("~/"), + sys.getfilesystemencoding()) return defaultDir - def getSamplesDir(self): - path = os.path.join(ankiqt.runningDir, "libanki") - if not os.path.exists(path): - path = os.path.join( - os.path.join(ankiqt.runningDir, ".."), "libanki") - if not os.path.exists(path): - path = ankiqt.runningDir - if sys.platform.startswith("win32"): - path = os.path.split( - os.path.split(ankiqt.runningDir)[0])[0] - elif sys.platform.startswith("darwin"): - path = ankiqt.runningDir + "/../../.." - path = os.path.join(path, "samples") - path = os.path.normpath(path) - if os.path.exists(path): - if sys.platform.startswith("darwin"): - return self.openMacSamplesDir(path) - return path - return "" - - def openMacSamplesDir(self, path): - # some versions of macosx don't allow the open dialog to point inside - # a .App file, it seems - so we copy the files onto the desktop. - newDir = os.path.expanduser("~/Documents/Anki 0.9 Sample Decks") - import shutil - if os.path.exists(newDir): - files = os.listdir(path) - for file in files: - loc = os.path.join(path, file) - if not os.path.exists(os.path.join(newDir, file)): - shutil.copy2(loc, newDir) - return newDir - shutil.copytree(path, newDir) - return newDir - def updateRecentFiles(self, path): "Add the current deck to the list of recent files." path = os.path.normpath(path) @@ -762,6 +722,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) return True def inMainWindow(self): + return True return self.app.activeWindow() == self def onNew(self, initial=False, path=None): @@ -827,23 +788,27 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) self.deck = None self.moveToState("initial") - def onOpen(self, samples=False): + def onGetSharedDeck(self): + if not self.inMainWindow(): return + if not self.saveAndClose(hideWelcome=True): return + s = ui.getshared.GetShared(self, 0) + if not s.ok: + self.deck = None + self.moveToState("initial") + + def onGetSharedPlugin(self): + if not self.inMainWindow(): return + ui.getshared.GetShared(self, 1) + + def onOpen(self): if not self.inMainWindow(): return key = _("Deck files (*.anki)") - if samples: defaultDir = self.getSamplesDir() - else: defaultDir = self.getDefaultDir() + defaultDir = self.getDefaultDir() file = QFileDialog.getOpenFileName(self, _("Open deck"), defaultDir, key) file = unicode(file) if not file: return False - if samples: - # we need to copy into a writeable location - d = unicode( - os.path.join(self.documentDir, os.path.basename(file))) - if not os.path.exists(d): - shutil.copy(file, d) - file = d ret = self.loadDeck(file, interactive=True) if not ret: if ret is None: @@ -854,9 +819,6 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) self.updateRecentFiles(file) return True - def onOpenSamples(self): - self.onOpen(samples=True) - def onUnsavedTimer(self): QToolTip.showText( self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)), @@ -952,14 +914,12 @@ your deck.""")) def onWelcomeAnchor(self, str): if str == "new": self.onNew() - elif str == "sample": - self.onOpenSamples() elif str == "open": self.onOpen() + elif str == "sample": + self.onGetSharedDeck() elif str == "openrem": self.onOpenOnline() - elif str == "more": - self.onGetMoreDecks() if str == "addfacts": if not self.deck: self.onNew() @@ -1177,7 +1137,6 @@ day = :d""", d=yesterday) self.deck.newCardSpacing = self.mainWin.newCardScheduling.currentIndex() self.deck.revCardOrder = self.mainWin.revCardOrder.currentIndex() self.deck.setFailedCardPolicy(self.mainWin.failedCardsOption.currentIndex()) - self.deck.updateDynamicIndices() self.deck.startSession() self.deck.flushMod() self.moveToState("getQuestion") @@ -1403,9 +1362,6 @@ day = :d""", d=yesterday) def onActiveTags(self): ui.activetags.show(self) - def onGetMoreDecks(self): - QDesktopServices.openUrl(QUrl(ankiqt.appMoreDecks)) - # Importing & exporting ########################################################################## @@ -1417,9 +1373,20 @@ day = :d""", d=yesterday) def onExport(self): ui.exporting.ExportDialog(self) - # Cramming + # Cramming & Sharing ########################################################################## + def _copyToTmpDeck(self, name="cram.anki", tags=""): + ndir = tempfile.mkdtemp(prefix="anki") + path = os.path.join(ndir, name) + from anki.exporting import AnkiExporter + e = AnkiExporter(self.deck) + if tags: + e.limitTags = parseTags(tags) + path = unicode(path, sys.getfilesystemencoding()) + e.exportInto(path) + return (e, path) + def onCram(self): if self.deck.name() == "cram": ui.utils.showInfo( @@ -1433,14 +1400,7 @@ day = :d""", d=yesterday) return s = unicode(s) # open tmp deck - ndir = tempfile.mkdtemp(prefix="anki") - path = os.path.join(ndir, "cram.anki") - from anki.exporting import AnkiExporter - e = AnkiExporter(self.deck) - if s: - e.limitTags = parseTags(s) - path = unicode(path, sys.getfilesystemencoding()) - e.exportInto(path) + (e, path) = self._copyToTmpDeck(tags=s) if not e.exportedCards: ui.utils.showInfo(_("No cards matched the provided tags.")) return @@ -1484,6 +1444,79 @@ day = :d""", d=yesterday) self.reset() p.finish() + def onShare(self, tags): + pwd = os.getcwd() + # open tmp deck + (e, path) = self._copyToTmpDeck(name="shared.anki", tags=tags) + if not e.exportedCards: + ui.utils.showInfo(_("No cards matched the provided tags.")) + return + self.deck.startProgress() + self.deck.updateProgress() + d = DeckStorage.Deck(path) + # reset scheduling to defaults + d.newCardsPerDay = 20 + d.delay0 = 600 + d.delay1 = 600 + d.delay2 = 0 + d.hardIntervalMin = 0.333 + d.hardIntervalMax = 0.5 + d.midIntervalMin = 3.0 + d.midIntervalMax = 5.0 + d.easyIntervalMin = 7.0 + d.easyIntervalMax = 9.0 + d.syncName = None + d.suspended = u"Suspended" + self.deck.updateProgress() + d.updateAllPriorities() + d.utcOffset = 24 + d.flushMod() + d.save() + self.deck.updateProgress() + # remove indices + indices = d.s.column0( + "select name from sqlite_master where type = 'index'") + for i in indices: + d.s.statement("drop index %s" % i) + # and q/a cache + d.s.statement("update cards set question = '', answer = ''") + self.deck.updateProgress() + d.s.statement("vacuum") + self.deck.updateProgress() + nfacts = d.factCount + mdir = d.mediaDir() + d.close() + dir = os.path.dirname(path) + zippath = os.path.join(dir, "shared-%d.zip" % time.time()) + # zip it up + zip = zipfile.ZipFile(zippath, "w", zipfile.ZIP_DEFLATED) + zip.writestr("facts", str(nfacts)) + readmep = os.path.join(dir, "README.html") + readme = open(readmep, "w") + readme.write('''\ + +This is an exported packaged deck created by Anki.

+ +To share this deck with other people, upload it to + +http://anki.ichi2.net/file/upload, or email +it to your friends. +''') + readme.close() + zip.write(readmep, "README.txt") + zip.write(path, "shared.anki") + if mdir: + for f in os.listdir(mdir): + zip.write(os.path.join(mdir, f), + str(os.path.join("shared.media/", f))) + shutil.rmtree(mdir) + self.deck.updateProgress() + zip.close() + os.chdir(pwd) + os.unlink(path) + self.deck.finishProgress() + self.onOpenPluginFolder(dir) + # Reviewing and learning ahead ########################################################################## @@ -1700,10 +1733,12 @@ day = :d""", d=yesterday) s = SIGNAL("triggered()") self.connect(m.actionNew, s, self.onNew) self.connect(m.actionOpenOnline, s, self.onOpenOnline) + self.connect(m.actionDownloadSharedDeck, s, self.onGetSharedDeck) + self.connect(m.actionDownloadSharedPlugin, s, self.onGetSharedPlugin) self.connect(m.actionOpen, s, self.onOpen) - self.connect(m.actionOpenSamples, s, self.onOpenSamples) self.connect(m.actionSave, s, self.onSave) self.connect(m.actionSaveAs, s, self.onSaveAs) + self.connect(m.actionShare, s, self.onShare) self.connect(m.actionClose, s, self.onClose) self.connect(m.actionExit, s, self, SLOT("close()")) self.connect(m.actionSyncdeck, s, self.syncDeck) @@ -1744,7 +1779,6 @@ day = :d""", d=yesterday) self.connect(m.actionDisableAllPlugins, s, self.onDisableAllPlugins) self.connect(m.actionActiveTags, s, self.onActiveTags) self.connect(m.actionReleaseNotes, s, self.onReleaseNotes) - self.connect(m.actionGetMoreDecks, s, self.onGetMoreDecks) self.connect(m.actionCacheLatex, s, self.onCacheLatex) self.connect(m.actionUncacheLatex, s, self.onUncacheLatex) self.connect(m.actionStudyOptions, s, self.onStudyOptions) @@ -1912,6 +1946,7 @@ day = :d""", d=yesterday) sys.path.insert(0, plugdir) plugins = self.enabledPlugins() plugins.sort() + self.registeredPlugins = {} for plugin in plugins: try: nopy = plugin.replace(".py", "") @@ -1919,6 +1954,7 @@ day = :d""", d=yesterday) except: print "Error in %s" % plugin traceback.print_exc() + self.checkForUpdatedPlugins() def rebuildPluginsMenu(self): if getattr(self, "pluginActions", None) is None: @@ -1950,13 +1986,15 @@ day = :d""", d=yesterday) return [p for p in os.listdir(self.pluginsFolder()) if p.endswith(".py.off") or p.endswith(".py")] - def onOpenPluginFolder(self): + def onOpenPluginFolder(self, path=None): + if path is None: + path = self.pluginsFolder() if sys.platform == "win32": # reuse our process handling code from latex - anki.latex.call(["explorer", self.pluginsFolder().encode( + anki.latex.call(["explorer", path.encode( sys.getfilesystemencoding())]) else: - QDesktopServices.openUrl(QUrl("file://" + self.pluginsFolder())) + QDesktopServices.openUrl(QUrl("file://" + path)) def onGetPlugins(self): QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins")) @@ -1988,6 +2026,14 @@ day = :d""", d=yesterday) self.enablePlugin(plugin) self.rebuildPluginsMenu() + def registerPlugin(self, name, updateId): + src = os.path.basename(inspect.getfile(inspect.currentframe(1))) + self.registeredPlugins[src] = {'name': name, + 'id': updateId} + + def checkForUpdatedPlugins(self): + pass + # Font localisation ########################################################################## @@ -2019,9 +2065,9 @@ day = :d""", d=yesterday) ########################################################################## def setupProgressInfo(self): - addHook("startProgress", self.onStartProgress) - addHook("updateProgress", self.onUpdateProgress) - addHook("finishProgress", self.onFinishProgress) + addHook("startProgress", self.startProgress) + addHook("updateProgress", self.updateProgress) + addHook("finishProgress", self.finishProgress) addHook("dbProgress", self.onDbProgress) addHook("dbFinished", self.onDbFinished) self.progressParent = None @@ -2032,7 +2078,7 @@ day = :d""", d=yesterday) def setProgressParent(self, parent): self.progressParent = parent - def onStartProgress(self, max=100, min=0, title=None): + def startProgress(self, max=0, min=0, title=None): if self.mainThread != QThread.currentThread(): return self.setBusy() @@ -2042,14 +2088,14 @@ day = :d""", d=yesterday) p = ui.utils.ProgressWin(parent, max, min, title) self.progressWins.append(p) - def onUpdateProgress(self, label=None, value=None): + def updateProgress(self, label=None, value=None): if self.mainThread != QThread.currentThread(): return if self.progressWins: self.progressWins[-1].update(label, value) self.app.processEvents() - def onFinishProgress(self): + def finishProgress(self): if self.mainThread != QThread.currentThread(): return if self.progressWins: diff --git a/ankiqt/ui/view.py b/ankiqt/ui/view.py index 6e85d7069..17555f1f1 100644 --- a/ankiqt/ui/view.py +++ b/ankiqt/ui/view.py @@ -272,25 +272,18 @@ Start adding your own material.

Open Local Deck

- - - - -

Open Online Deck

- - -

Open Sample Deck

+

Download Shared Deck

- - + + -

Get More Decks

+

Download Personal Deck

""")) diff --git a/designer/exporting.ui b/designer/exporting.ui index 2a1838222..24d01c440 100644 --- a/designer/exporting.ui +++ b/designer/exporting.ui @@ -58,6 +58,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/designer/getshared.ui b/designer/getshared.ui new file mode 100644 index 000000000..be320961d --- /dev/null +++ b/designer/getshared.ui @@ -0,0 +1,121 @@ + + Dialog + + + + 0 + 0 + 517 + 411 + + + + + + + + + Search: + + + + + + + + + + + + Qt::Vertical + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAlwaysOff + + + + + 0 + 0 + 494 + 54 + + + + + 0 + 0 + + + + + + + Loading... + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/designer/main.ui b/designer/main.ui index a1c955839..31eb78cd0 100644 --- a/designer/main.ui +++ b/designer/main.ui @@ -1174,7 +1174,6 @@ - @@ -1208,10 +1207,23 @@ :/icons/document-open-recent.png:/icons/document-open-recent.png + + + &Download... + + + + :/icons/document-open-remote.png:/icons/document-open-remote.png + + + + + + - + @@ -1288,7 +1300,6 @@ - @@ -1762,15 +1773,6 @@ Check Media Database... - - - - :/icons/document-open-remote.png:/icons/document-open-remote.png - - - Open On&line... - - @@ -1823,15 +1825,6 @@ Active &Tags... - - - - :/icons/download.png:/icons/download.png - - - &Get More Decks... - - @@ -1904,6 +1897,34 @@ &Record Noise Profile... + + + Get Shared... + + + Open a pre-made deck or plugin + + + + + Share... + + + + + Personal Deck + + + + + Shared Deck + + + + + Shared Plugin + + newPerDay diff --git a/designer/share.ui b/designer/share.ui new file mode 100644 index 000000000..0557422e4 --- /dev/null +++ b/designer/share.ui @@ -0,0 +1,134 @@ + + Dialog + + + + 0 + 0 + 517 + 411 + + + + Get Shared Decks/Plugins + + + + + + + + Search: + + + + + + + + + + Type: + + + + + + + + + + + + Qt::Vertical + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAlwaysOff + + + + + 0 + 0 + 494 + 54 + + + + + 0 + 0 + + + + + + + TextLabel + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +