10
Velké věci

### CGI: eKniha přání a stížností

% cat komentar.py

#!/usr/bin/python
import cgi, os, sys, string

def rozplyvameSe(data):
    print "Content-type: text/html\n"  #  
    print "<h3>Díky moc!</h3>"
    print "Komentáře našich zákazníků jsou pro nás strašně"
    print "důležíté. Řídí se jimi rozvoj naší firmy a pomáhají"
    print "Honzově karmě. <BR>Ještě jednou díky, Honza <BR>P.S."
    print "Další komentáře nám můžete zanechat prostým"
    print "opětovným odesláním formuláře."

def fnukame(data):
    print "Content-type: text/html\n"
    print "<h3>Moc se omlouváme!</h3>"
    print "Moc nás mrzí, že si musíte na naše produkty"
    print " stěžovat. Vaše výtky si samotřejmě pečlivě"
    print "pročítáme a už brzy dáme vědět, zda s tím něco"
    print "můžeme dělat. <BR>Tak jako tak díky za Váš čas."
    print "<BR>Váš Honza"

def vymahameZbytek():
    print "Content-type: text/html\n"
    print "<H3>Problémy ...</H3>"
    print "Vyplňte prosím formulář úplně celý.<P>"
    print '<a href="komentar.html">Zpět</a>'
    sys.exit()

class Formular:
    def __init__(self, form):
        for p in self.pole:
            if not form.has_key(p) or form[p].value == "":
                vymahameZbytek()
            else:
                setattr(self, p, form[p].value)

class Komentar(Formular):
    pole = ('jmeno', 'adresa', 'email', 'typ', 'text')
    def __repr__(self):
        if self.typ == 'stiznost': text = 'Stížnost'
        else: text = 'Komentář'
        return text + " od '%(jmeno)s' z %(cas)s" % vars(self)

ADRESAR = r'C:\komentare'

if __name__ == '__main__':
    sys.stderr = sys.stdout        # i chyby do textu stánky
    formular = cgi.FieldStorage()  # načtení vstupu
    data = Komentar(formular)      # kontrola vstupních dat
    if data.typ == 'komentar':
        rozplyvameSe(data)         # reakce – generované stránky
    else: 
        fnukame(data)

    import tempfile, pickle, time  # uložíme data
    tempfile.tempdir = ADRESAR
    data.cas = time.asctime(time.localtime(time.time()))
    pickle.dump(data, open(tempfile.mktemp(), 'w'))

form = cgi.FieldStorage()
form_ok = 1

if not form.has_key("jmeno") or form["jmeno"].value == "":
    form_ok = 0
else:
    data_name = form["name"].value

if not form.has_key("email") or form["email"].value == "":
    form_ok = 0
else:
    data_email = form["email"].value

...

### COM: levná sekretářka

from win32com.client import constants, Dispatch
import string

WORD = 'Word.Application.8' #  

class Word:
    def __init__(self):
        self.w = Dispatch(WORD)
    def otevrit(self, doc):
        self.w.Documents.Open(FileName=doc)
    def nahradit(self, co, cim):
        self.w.Selection.HomeKey(Unit=constants.wdLine) #  
        self.w.Selection.Find.Text = "%"+co+"%"
        self.w.Selection.Find.Execute()
        self.w.Selection.TypeText(Text=cim)
    def tisk(self):
        self.w.Application.PrintOut()
    def zavrit(self):
        self.w.ActiveDocument.Close(SaveChanges=0)

def tiskDopisu(data):
    word.otevrit(r"c:\sablona.doc")
    word.nahradit("stezovatel", data.jmeno)
    word.nahradit("adresa", data.adresa)
    word.tisk()
    word.zavrit()

if __name__ == '__main__':
    import os, pickle
    from komentar import ADRESAR, Formular, Komentar
    word = Word()
    for soub in os.listdir(ADRESAR):
        data = pickle.load(open(os.path.join(ADRESAR, soub)))
        if data.typ == 'stiznost':
            print "Tiskneme dopis pro '%(jmeno)s'." % vars(data)
            tiskDopisu(data)
        else:
            print "%(name)s posílá jen komentář." % vars(data)

C:\Python> python dopis.py 
Tiskneme dopis pro 'Petr Dvořák'.
Jana Chovatelová posílá jen komentář.
Tiskneme dopis pro 'Alex Novák'.

### Tkinter: prohlížeč a abstrakce

from Tkinter import mainloop
from prohlizec import Prohlizec 
from komentar import Komentar  #  

Prohlizec(Komentar, r"c:\komentare")
mainloop()

from Tkinter import *
import string, os, pickle

class Prohlizec:
    def __init__(self, dataTrida, dataAdresar):
        self.dataAdresar = dataAdresar        # skatule, skatule
        self.dataTrida = dataTrida            #  hejbejte se
        self.guiRadek = 0
        self.guiOkno = guiOkno = Tk()         # vytvoříme okno
        guiOkno.minsize(300,200)              # nast. velikost

        guiOkno.rowconfigure(0, weight=1)     # chování okna
        guiOkno.columnconfigure(0, weight=1)  #  při zvětšování
        guiOkno.columnconfigure(1, weight=2)  #  

        self.guiSeznam = Listbox(guiOkno, selectmode=SINGLE)
        self.guiSeznam.grid(columnspan=2, sticky=E+W+N+S)
        self.guiSeznam.bind('<ButtonRelease-1>',
                            self.vyberPolozku)
        self.guiRadek += 1

        for jmeno in dataTrida.pole:
           setattr(self, jmeno, self.pridejPole(guiOkno, jmeno))      

        self.pridejTlacitko(self.guiOkno, self.guiRadek, 0, 
                            'Vymaž položku', self.vymazPolozku)
        self.pridejTlacitko(self.guiOkno, self.guiRadek, 1, 
                           'Načti znovu', self.nactiData)
        self.nactiData()

self.jmeno = self.pridejPole(guiOkno, 'jmeno')
self.email = self.pridejPole(guiOkno, 'email')
self.adresa = self.pridejPole(guiOkno, 'adresa')
self.typ = self.pridejPole(guiOkno, 'typ')
self.text = self.pridejPole(guiOkno, 'text')

def pridejPole(self, guiOkno, jmeno):
    Label(guiOkno, text=jmeno).grid(row=self.guiRadek,
          column=0, sticky=E)
    hodnota = Label(guiOkno, text='', background='gray90',
                    relief=SUNKEN, anchor=W, justify=LEFT)
    hodnota.grid(row=self.guiRadek, column=1, sticky=E+W)
    self.guiRadek += 1
    return hodnota

def pridejTlacitko(self, guiOkno, guiRadek, guiSloupec, 
                   text, prikaz):
    button = Button(guiOkno, text=text, command=prikaz)
    button.grid(row=guiRadek, column=guiSloupec, sticky=E+W,
                padx=5, pady=5)

def nactiData(self):
    self.guiSeznam.delete(0,END)
    self.data = []
    for dataJmeno in os.listdir(self.dataAdresar):
        polozka = pickle.load(open( \
                   os.path.join(self.dataAdresar, dataJmeno)))
        polozka._dataJmeno = dataJmeno
        self.data.append(polozka)
        self.guiSeznam.insert('end', `polozka`)
    self.guiSeznam.select_set(0)
    self.vyberPolozku(None)

def vyberPolozku(self, udalost):
    vyber = self.guiSeznam.curselection()
    self.vyber = self.data[int(vyber[0])]
    for pole in self.dataTrida.pole:
        guiPole = getattr(self, pole)
        guiPoleText = getattr(self.vyber, pole)
        guiPoleText = string.replace(guiPoleText,'\r', '')  #   
        guiPole.config(text=guiPoleText)

 def vymazPolozku(self):
     os.remove(os.path.join(self.dataAdresar,
                            self.selection._dataJmeno))
     self.nactiData()

### Návrh: CGI vs. Tkinter?

### Jython = Python + Java

C:\jython-2.1>jython
Jython 2.1 on java1.3.0 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> 2 + 3
5

from pawt import swing
import java

def konec(e): java.lang.System.exit(0)

okno = swing.JFrame('Swing!', visible=1)
tlacitko = swing.JButton('Tak tohle je Swing',
                         actionPerformed=konec)
okno.contentPane.add(tlacitko)
okno.pack()

from pawt import swing, awt, colors, GridBag

VPRAVO = swing.JLabel.RIGHT
MUZEM = swing.JFileChooser.APPROVE_OPTION

import java.io
import pickle, os

uvodniKod = """from math import *
def naseFce(x, rad):
    celkem = 0.0
    for i in range(1, rad*2+1, 2):
        celkem += sin(x*i/10.0)/(float(i))
    return celkem
"""
uvodniVyraz = "naseFce(x, rad=3)"

class Graf(awt.Canvas):
    barva = colors.darkturquoise
    styl = 'Vypln'

    # přetěžujeme met. awt.Canvas
    def getPreferredSize(self):
        return awt.Dimension(600,300)

    def paint(self, kam):
        meze = self.bounds
        kam.color = colors.white
        kam.fillRect(0, 0, meze.width, meze.height)

        sirka = int(meze.width * .8)
        vyska = int(meze.height * .8)
        poziceX = int(meze.width * .1)
        poziceY = meze.height - int(meze.height * .1)

        N = len(self.data);
        bodyX = [0]*N; bodyY = [0]*N

        minX, maxX = 0, N-1
        maxY = max(self.data); minY = min(self.data)

        pocatekY = poziceY - int(-minY/(maxY-minY)*vyska)
        pocatekX = poziceX + int(-minX/(maxX-minX)*sirka)

        for i in range(N):
            bodyX[i] = int(float(i)*sirka/N) + poziceX
            bodyY[i] = poziceY - int((self.data[i]-minY)/\
                                     (maxY-minY)*vyska)
        kam.color = self.barva

        if self.styl == "Cara":
            kam.drawPolyline(bodyX, bodyY, len(bodyX))
        else:
            bodyX.insert(0, bodyX[0]); bodyY.insert(0, pocatekY)
            bodyX.append(bodyX[-1]); bodyY.append(pocatekY)
            kam.fillPolygon(bodyX, bodyY, len(bodyX))

        # vykreslíme osy
        kam.color = colors.black
        kam.drawLine(poziceX, pocatekY, 
                     poziceX + sirka, pocatekY)
        kam.drawLine(pocatekX, poziceY, 
                     pocatekX, poziceY - vyska)

        # vykreslíme popisky
        kousek = kam.font.size
        kam.drawString("%.3f" % minX, 
                       poziceX, pocatekY + kousek)
        kam.drawString("%.3f" % maxX, 
                       poziceX + sirka, pocatekY + kousek)
        kam.drawString("%.3f" % minY, 
                       pocatekX - 50, poziceY)
        kam.drawString("%.3f" % maxY, 
                       pocatekX - 50, poziceY - vyska + kousek)

class GUI:
    def __init__(self):
        self.pocetBodu = 100
        self.okno = swing.JFrame("Grafy",
                                 windowClosing=self.konec)

        # sestavíme menu
        menu = swing.JMenuBar()
        menuSoubor = swing.JMenu("Soubor")
        menuSoubor.add(swing.JMenuItem("Otevřít",
                       actionPerformed = self.otevrit))
        menuSoubor.add(swing.JMenuItem("Uložit", 
                       actionPerformed = self.ulozit))
        menuSoubor.add(swing.JMenuItem("Konec", 
                       actionPerformed = self.konec))
        menu.add(menuSoubor)
        self.okno.JMenuBar = menu

        self.Graf = Graf(visible=1)
        self.vstupKod = swing.JTextArea(uvodniKod, 8, 60)
        self.vstupVyraz = swing.JTextField(uvodniVyraz,
                           actionPerformed = self.aktualizovat)

        # různá nastaveni:
        panelMoznosti = swing.JPanel(awt.FlowLayout(
            alignment=awt.FlowLayout.LEFT))

        # máme vykreslovat jako čáru nebo souvislou plochu?
        self.vypln = swing.JRadioButton("Výplň",
                      actionPerformed=self.nastavitStylVypln)
        panelMoznosti.add(self.vypln)
        self.cara = swing.JRadioButton("Čára",
                     actionPerformed=self.nastavitStylCara)
        panelMoznosti.add(self.cara)
        vyberStylu = swing.ButtonGroup()
        vyberStylu.add(self.vypln) 
        vyberStylu.add(self.cara)

        # výběr barvy
        panelMoznosti.add(swing.JLabel("Barva:", VPRAVO))
        barvy = filter(lambda x: x[0] != '_', dir(colors))
        self.vyberBarvy = swing.JComboBox(barvy)
        self.vyberBarvy.itemStateChanged = self.nastavitBarvu
        panelMoznosti.add(self.vyberBarvy)

        # výběr počtu bodu
        panelMoznosti.add(swing.JLabel("Počet bodů:", VPRAVO))
        self.pocetBoduMoznosti = [50, 100, 200, 500]
        self.vyberPoctuBodu = \
         swing.JComboBox(self.pocetBoduMoznosti)
        self.vyberPoctuBodu.selectedIndex = \
         self.pocetBoduMoznosti.index(self.pocetBodu)
        self.vyberPoctuBodu.itemStateChanged = \
         self.nastavitPocetBodu
        panelMoznosti.add(self.vyberPoctuBodu)

        # dokončení - poskládáme všechno do "jako tabulky"
        self.nahodit(panelMoznosti)

    def nahodit(self, panelMoznosti):
        tabulka = GridBag(self.okno.contentPane, fill='BOTH',
                          weightx=1.0, weighty=1.0)
        tabulka.add(swing.JLabel("Inicial.: ", VPRAVO))
        tabulka.addRow(swing.JScrollPane(self.vstupKod),
                                         weighty=10.0)
        tabulka.add(swing.JLabel("Výraz: ", VPRAVO))
        tabulka.addRow(self.vstupVyraz, weighty=2.0)
        tabulka.add(swing.JLabel("Výstup: ", VPRAVO))
        tabulka.addRow(self.Graf, weighty=20.0)
        tabulka.add(swing.JLabel("Nastavení: ", VPRAVO))
        tabulka.addRow(panelMoznosti, weighty=2.0)

        self.aktualizovat(None)
        self.okno.visible = 1
        self.okno.size = self.okno.getPreferredSize()

        self.vyberSouboru = swing.JFileChooser()
        self.vyberSouboru.currentDirectory = \
         java.io.File(os.getcwd())

    def ulozit(self, zprav=None):
        self.vyberSouboru.rescanCurrentDirectory()
        navratova = self.vyberSouboru.showSaveDialog(self.okno)
        if navratova == MUZEM:
            objekt = (self.vstupKod.text, self.vstupVyraz.text,
                      self.Graf.styl, self.Graf.barva.RGB,
                      self.vyberBarvy.selectedIndex,
                      self.pocetBodu)
            soubor = open(os.path.join( \
                      self.vyberSouboru.currentDirectory.path,
                      self.vyberSouboru.selectedFile.name), 'w')
            pickle.dump(objekt, soubor)
            soubor.close()

    def otevrit(self, zprav=None):
        self.vyberSouboru.rescanCurrentDirectory()
        navratova = self.vyberSouboru.showOpenDialog(self.okno)
        if navratova == MUZEM:
            soubor = open(os.path.join( \
                      self.vyberSouboru.currentDirectory.path,
                      self.vyberSouboru.selectedFile.name))
            (kod, vyraz, styl, barva, 
             vyberBarvy, self.pocetBodu) = pickle.load(soubor)
            soubor.close()
            self.Graf.barva = java.awt.Color(barva)
            self.vyberBarvy.selectedIndex = vyberBarvy
            self.Graf.styl = styl
            self.vstupKod.text = kod
            self.pocetBodu.volba = \
             self.pocetBoduMoznosti.index(self.pocetBodu)
            self.vstupVyraz.text = vyraz
            self.aktualizovat(None)

    def konec(self, zprav=None):
        import sys
        sys.exit(0)

    def nastavitBarvu(self, zprav):
        self.Graf.barva = getattr(colors, zprav.item)
        self.Graf.repaint()

    def nastavitPocetBodu(self, zprav):
        self.pocetBodu = zprav.item
        self.aktualizovat(None)

    def nastavitStylVypln(self, zprav):
        self.Graf.styl = 'Vypln'
        self.Graf.repaint()

    def nastavitStylCara(self, zprav):
        self.Graf.styl = 'Cara'
        self.Graf.repaint()

    def aktualizovat(self, zprav):
        jmennyProstor = {}
        exec self.vstupKod.text in jmennyProstor
        pokazde = \
         compile(self.vstupVyraz.text, '<input>', 'eval')
        hodnoty = [0]*self.pocetBodu

        for x in range(self.pocetBodu):
            jmennyProstor['x'] = float(x)
            hodnoty[x] = eval(pokazde, jmennyProstor)

        self.Graf.data = hodnoty
        if self.Graf.styl == 'Cara': self.cara.setSelected(1)
        else: self.vypln.setSelected(1)
        self.Graf.repaint()

GUI()

### Další knihovny

>>> from Numeric import *
>>> souradnice = arange(-6, 6, 0.2)  # pole
>>> xs = sin(souradnice)             # další pole
>>> ys = cos(souradnice) * exp(-souradnice*souradnice/18.0)
>>> zs = xs * ys[:, NewAxis]         # jejich součin

### Cvičení