diff options
Diffstat (limited to 'equations')
-rw-r--r-- | equations/models.py | 119 | ||||
-rw-r--r-- | equations/signals.py | 65 | ||||
-rw-r--r-- | equations/templates/equations/equation_detail.html | 27 | ||||
-rw-r--r-- | equations/templates/equations/equation_list.html | 24 | ||||
-rw-r--r-- | equations/views.py | 31 |
5 files changed, 264 insertions, 2 deletions
diff --git a/equations/models.py b/equations/models.py index 71a8362..6791eb2 100644 --- a/equations/models.py +++ b/equations/models.py @@ -1,3 +1,120 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ +import django.contrib.auth.models as auth +from django.conf import settings +from django.dispatch import dispatcher +from django.db.models import signals +from signals import update_render -# Create your models here. +class Symbol(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + renderdir = "symbolrenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + + class Meta: + get_latest_by = 'name' + class Admin: + ordering = ['name'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/symbol/%s/" % self.id + def get_admin_url(self): + return "/admin/symbols/%s/" % self.id + #def save(self): + # super(Symbol, self) + # self.update_generic_variable() + def save(self): + super(Symbol, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Symbol, self).save() + +def update_generic_variable(sender, instance, signal, *args, **kwargs): + """Checks if there is a generic variable associated with this + symbol; create one if there isn't""" + for v in Variable.objects.filter(isgeneric=True): + if v.latex == instance.latex: + return + genericv = Variable(name="Generic %s" % instance.name, + latex=instance.latex, + unicode=instance.unicode, + symbol=instance, + isgeneric=True) + genericv.save() + +dispatcher.connect(update_render, signal=signals.pre_save, sender=Symbol) +dispatcher.connect(update_generic_variable, signal=signals.post_save, + sender=Symbol) + +class Variable(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + description = models.TextField(_("Description"), blank=True) + renderdir = "variablerenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + reference = models.URLField(_("Reference URL"), blank=True) + symbol = models.ForeignKey(Symbol, verbose_name=_("Symbol")) + isgeneric = models.BooleanField(_("Is Generic?"), default=False) + + class Meta: + get_latest_by = 'name' + class Admin: + ordering = ['name'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/variable/%s/" % self.id + def get_admin_url(self): + return "/admin/variables/%s/" % self.id + def save(self): + super(Variable, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Variable, self).save() + +dispatcher.connect(update_render, signal=signals.pre_save, sender=Variable) + +class Equation(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + description = models.TextField(_("Description"), blank=True) + created = models.DateField(_("Created"), auto_now_add=True) + updated = models.DateField(_("Last Updated"), auto_now_add=True) + owner = models.ForeignKey(auth.User, verbose_name=_("Owner")) + variables = models.ManyToManyField(Variable, verbose_name="Variables", + editable=True) + renderdir = "equationrenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + reference = models.URLField(_("Reference URL"), blank=True) + + class Meta: + get_latest_by = 'created' + class Admin: + ordering = ['created'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/equation/%s/" % self.id + def get_admin_url(self): + return "/admin/equations/%s/" % self.id + def update_variables(self): + """Updates the variables field with all Variable objects found + in the LaTeX representation.""" + pass # TODO: write + def save(self): + self.update_variables() + super(Equation, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Equation, self).save() + + +dispatcher.connect(update_render, signal=signals.post_save, sender=Equation) diff --git a/equations/signals.py b/equations/signals.py new file mode 100644 index 0000000..0fecc34 --- /dev/null +++ b/equations/signals.py @@ -0,0 +1,65 @@ +from django.conf import settings + +def update_render(sender, instance, signal, *args, **kwargs): + """Renders an object's .png representation using LaTeX and puts it + in the right directory. Requires latex, dvipng, etc""" + import os, shutil, tempfile, subprocess + def call_command_in_dir(app, args, targetdir): + cwd = os.getcwd() + try: + os.chdir(targetdir) + p = subprocess.Popen(app + ' ' + ' '.join(args), shell=True) + sts = os.waitpid(p.pid, 0) + # FIXME -- should we raise an exception of status is non-zero? + finally: + # Restore working directory + os.chdir(cwd) + + rawlatex = instance.latex + dstdir = settings.MEDIA_ROOT + instance.renderdir + dstfile = "%s.png" % instance.id + dst = "%s" % instance.id + + prologue = "" + latex_template = r''' + \documentclass[12pt]{article} + \pagestyle{empty} + %(prologue)s + \begin{document} + $$%(raw)s$$ + \end{document} + ''' + max_pages = 1 + MAX_RUN_TIME = 5 # seconds + latex = "latex" + dvipng = "dvipng" + latex_args = ("--interaction=nonstopmode", "%s.tex") + dvipng_args = ("-q", "-bgTransparent", "-Ttight", "--noghostscript", + "-l%s" % max_pages, "%s.dvi") + tex = latex_template % { 'raw': rawlatex, 'prologue': prologue } + + tmpdir = tempfile.mkdtemp() + try: + data = open("%s/%s.tex" % (tmpdir, dst), "w") + data.write(tex) + data.close() + args = list(latex_args) + args[-1] = args[-1] % dst + res = call_command_in_dir(latex, args, tmpdir) + if not res is None: + # FIXME need to return some sort of error + return [] + args = list(dvipng_args) + args[-1] = args[-1] % dst + res = call_command_in_dir(dvipng, args, tmpdir) + if not res is None: + # FIXME need to return some sort of error + return [] + + if os.access("%s/%s1.png" % (tmpdir, dst), os.R_OK): + shutil.copyfile("%s/%s1.png" % (tmpdir, dst), + dstdir + dstfile) + finally: + # FIXME do some tidy up here + instance.render = instance.renderdir + dstfile + shutil.rmtree(tmpdir) diff --git a/equations/templates/equations/equation_detail.html b/equations/templates/equations/equation_detail.html new file mode 100644 index 0000000..b4c3911 --- /dev/null +++ b/equations/templates/equations/equation_detail.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %}{{ object.name }}{% endblock %} + +{% block content %} +<div style="width: 100px; text-align:center;"> +<img src="{{ object.get_render_url }}" style="border: none;" /></div> +<table width="100%"> +{% if object.description %} + <tr><td><b>Description:</b></td><td>{{ object.description }}</td></tr> +{% endif %} +{% if object.variables %} + <tr><td><b>Variables:</b></td><td> + {% for variable in object.variables %} + <a href="{{ variable.get_absolute_url }}">{{ variable.name }}</a><br /> + {% endfor %} +{% endif %} + <tr><td><b>Raw LaTeX:</b></td><td>{{ object.latex }}</td></tr> +{% if object.unicode %} + <tr><td><b>Unicode:</b></td><td>{{ object.unicode }}</td></tr> +{% endif %} + <tr><td></td><td><br /> + This equation was created on <i>{{ object.created }}</i>; + it was last updated on <i>{{ object.updated }}</i>. It's owner is + <i>{{ object.owner }}</i>.</td></tr> +</table> +{% endblock %} diff --git a/equations/templates/equations/equation_list.html b/equations/templates/equations/equation_list.html new file mode 100644 index 0000000..c7a9632 --- /dev/null +++ b/equations/templates/equations/equation_list.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block title %}Check out all these equations!{% endblock %} + +{% block content %} +{% if object_list %} +<table width="!00%"> + {% for item in object_list %} + <tr style="height:50px;"><td style="width:45%;"> + <a href="{{ item.get_absolute_url }}" class="imglink"> + <img style="border: none;" src="{{ item.get_render_url }}" /></a> + </td><td style="width: 55%"><a href="{{ item.get_absolute_url }}"> + {{ item.name }}</a></td></tr> + {% endfor %} +</table> +{% if not is_paginated %}<br />{% if not has_previous %} +<b><a href="./?page={{ previous }}" style="float:left;"><PREV</a></b> +{% endif %}{% if has_next %} +<b><a href="./?page={{ next }}" style="float:right;">NEXT></a></b> +{% endif %}{% endif %} +{% else %} +Fuck, where are they? +{% endif %} +{% endblock %} diff --git a/equations/views.py b/equations/views.py index 60f00ef..8e2f6fa 100644 --- a/equations/views.py +++ b/equations/views.py @@ -1 +1,30 @@ -# Create your views here. +from django.core import serializers +from models import Equation, Variable, Symbol +from django.http import HttpResponse + +def all_vars(request): + data = serializers.serialize("json", Variable.objects.all()) + return HttpResponse(data, mimetype="text/javascript") + +def all_symbs(request): + data = serializers.serialize("json", Symbol.objects.all()) + return HttpResponse(data, mimetype="text/javascript") + +def equs_by_vars(request, whichvars): + vars = whichvars.split(',') + if len(vars) < 1: + return HttpResponse('[]', mimetype="text/javascript") + #if vars[-1] == '/': + # vars = vars[:-1] + returnables = Equation.objects.filter(variables=vars[0]) + if len(vars) > 1: + for r in returnables: + for i in vars[1:]: + if not i in r.variables: + returnables = returnables.exclude(id=r.id) + if len(returnables) < 1: + break + + data = serializers.serialize("json", returnables) + return HttpResponse(data, mimetype="text/javascript") + |