# -*- 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 * import ankiqt, simplejson, time, cStringIO, zipfile, tempfile, os, re import traceback, urllib2 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) 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.connect(self.form.search, SIGNAL("textChanged(QString)"), self.limit) def fetchData(self): try: sock = urllib2.urlopen( "http://anki.ichi2.net/file/search?t=%d" % self.type) self.allList = simplejson.loads(unicode(sock.read())) except: showInfo(_("Unable to connect to server.\n\n") + traceback.format_exc()) self.close() return self.form.search.setFocus() self.typeChanged() self.limit() def limit(self, txt=""): if not txt: self.curList = self.allList else: txt = unicode(txt).lower() self.curList = [ l for l in self.allList if (txt in l[R_TITLE].lower() or txt in l[R_DESCRIPTION].lower() or txt in l[R_TAGS].lower())] 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_COUNT) else: cols = (R_TITLE, R_COUNT, R_MODIFIED) for rc, r in enumerate(self.curList): for cc, c in enumerate(cols): if c == R_FACTS or c == R_COUNT: txt = unicode("%15d" % r[c]) elif c == R_MODIFIED: days = int(((time.time() - r[c])/(24*60*60))) txt = ngettext("%6d day ago", "%6d days ago", days) % days else: txt = unicode(r[c]) item = QTableWidgetItem(txt) item.setFlags(item.flags() & ~Qt.ItemIsEditable) self.items[item] = r self.form.table.setItem(rc, cc, item) self.form.table.setSortingEnabled(True) if self.type == 0: self.form.table.sortItems(2, Qt.DescendingOrder) else: self.form.table.sortItems(1, Qt.DescendingOrder) self.form.table.selectRow(0) self.onCellChanged(None, None, None, None) 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
Modified: %(mod)s ago

%(description)s""") % { 'title': r[R_TITLE], 'tags': r[R_TAGS], 'size': r[R_SIZE] / 1024.0, 'author': r[R_USERNAME], 'count': r[R_COUNT], 'mod': fmtTimeSpan(time.time() - r[R_MODIFIED]), '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"), _("Downloads")]) else: self.form.table.setColumnCount(3) self.form.table.setHorizontalHeaderLabels([ _("Title"), _("Downloads"), _("Modified")]) self.form.table.horizontalHeader().setResizeMode( 0, QHeaderView.Stretch) self.form.table.verticalHeader().hide() def accept(self): if self.type == 0: if not self.parent.saveAndClose(hideWelcome=True, parent=self): return QDialog.accept(self) (fd, tmpname) = tempfile.mkstemp(prefix="anki") tmpfile = os.fdopen(fd, "w+b") cnt = 0 try: self.parent.setProgressParent(self) self.parent.startProgress() try: sock = urllib2.urlopen( "http://anki.ichi2.net/file/get?id=%d" % self.curRow[R_ID]) while 1: data = sock.read(65536) if not data: break cnt += len(data) tmpfile.write(data) self.parent.updateProgress( label=_("Downloaded %dKB") % (cnt/1024.0)) except: showInfo(_("Unable to connect to server.\n\n") + traceback.format_exc()) self.close() return finally: self.parent.setProgressParent(None) self.parent.finishProgress() QDialog.accept(self) # file is fetched tmpfile.seek(0) self.handleFile(tmpfile) QDialog.accept(self) def handleFile(self, file): ext = os.path.splitext(self.curRow[R_FNAME])[1] if ext == ".zip": z = zipfile.ZipFile(file) 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, "wb").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)),"wb").write(z.read(l)) self.parent.loadDeck(dpath) else: pd = self.parent.pluginsFolder() if z: for l in z.infolist(): if not l.file_size: continue try: os.makedirs(os.path.join( pd, os.path.dirname(l.filename))) except OSError: pass open(os.path.join(pd, l.filename), "wb").\ write(z.read(l.filename)) else: open(os.path.join(pd, tit + ext), "wb").write(file.read()) showInfo(_("Plugin downloaded. Please restart Anki."), parent=self)