Merge branch 'master' of repos.ctdo.de:psychose

This commit is contained in:
Lucas Pleß 2014-10-28 19:33:52 +01:00
commit 1b99af1219
53 changed files with 5115 additions and 3224 deletions

View File

@ -15,17 +15,17 @@ set -g terminal-overrides 'xterm*:smcup@:rmcup@'
new-session -s 'csession'
attach-session -t 'csession'
new-window -n 'socat-ekg-merle' -t 'csession:3' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-ekg-uwe' -t 'csession:4' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-ekg-bjoern' -t 'csession:2' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-ekg-merle' -t 'csession:3' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-merle-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ekg2osc-merle-out,b115200,user=sarah'
new-window -n 'socat-ekg-uwe' -t 'csession:4' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-out,b115200,user=sarah'
new-window -n 'socat-ekg-bjoern' -t 'csession:2' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-out,b115200,user=sarah'
new-window -n 'socat-pulse-merle' -t 'csession:6' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-pulse-uwe' -t 'csession:7' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-pulse-bjoern' -t 'csession:5' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-pulse-merle' -t 'csession:6' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-merle-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/pulse2osc-merle-out,b115200,user=sarah'
new-window -n 'socat-pulse-uwe' -t 'csession:7' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-out,b115200,user=sarah'
new-window -n 'socat-pulse-bjoern' -t 'csession:5' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-out,b115200,user=sarah'
new-window -n 'socat-ehealth-merle' -t 'csession:9' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-ehealth-uwe' -t 'csession:10' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-ehealth-bjoern' -t 'csession:8' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-ehealth-merle' -t 'csession:9' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-out,b115200,user=sarah'
new-window -n 'socat-ehealth-uwe' -t 'csession:10' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-out,b115200,user=sarah'
new-window -n 'socat-ehealth-bjoern' -t 'csession:8' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-in,b115200,user=sarah PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-out,b115200,user=sarah'
new-window -n 'ekg2osc-merle' -t 'csession:11' 'ekgmerle -D /tmp/ekg2osc-merle-out'
new-window -n 'ekg2osc-uwe' -t 'csession:12' 'ekguwe -D /tmp/ekg2osc-uwe-out'
@ -39,17 +39,17 @@ new-window -n 'ehealth2osc-merle' -t 'csession:17' 'sleep 1 && ehealthmerle -
new-window -n 'ehealth2osc-uwe' -t 'csession:18' 'sleep 1 && ehealthuwe -D /tmp/ehealth2osc-uwe-out'
new-window -n 'ehealth2osc-bjoern' -t 'csession:19' 'sleep 1 && ehealthbjoern -D /tmp/ehealth2osc-bjoern-out'
new-window -n 'test-ekg-merle' -t 'csession:21' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-merle-in'
new-window -n 'test-ekg-uwe' -t 'csession:22' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-uwe-in'
new-window -n 'test-ekg-bjoern' -t 'csession:20' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-bjoern-in'
new-window -n 'test-ekg-merle' -t 'csession:21' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-merle-in'
new-window -n 'test-ekg-uwe' -t 'csession:22' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-uwe-in'
new-window -n 'test-ekg-bjoern' -t 'csession:20' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-bjoern-in'
new-window -n 'test-pulse-merle' -t 'csession:24' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-merle-in'
new-window -n 'test-pulse-uwe' -t 'csession:25' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-uwe-in'
new-window -n 'test-pulse-bjoern' -t 'csession:23' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-bjoern-in'
new-window -n 'test-pulse-merle' -t 'csession:24' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-merle-in'
new-window -n 'test-pulse-uwe' -t 'csession:25' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-uwe-in'
new-window -n 'test-pulse-bjoern' -t 'csession:23' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-bjoern-in'
new-window -n 'test-ehealth-merle' -t 'csession:27' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-merle-in'
new-window -n 'test-ehealth-uwe' -t 'csession:28' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-uwe-in'
new-window -n 'test-ehealth-bjoern' -t 'csession:26' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-bjoern-in'
new-window -n 'test-ehealth-merle' -t 'csession:27' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-merle-in'
new-window -n 'test-ehealth-uwe' -t 'csession:28' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-uwe-in'
new-window -n 'test-ehealth-bjoern' -t 'csession:26' 'python /home/sarah/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-bjoern-in'
select-window -t 'csession:2'

View File

@ -10,6 +10,28 @@
<height>606</height>
</rect>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>14</pointsize>
<italic>true</italic>
</font>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGraphicsView" name="graphics_view">
<property name="minimumSize">
<size>
<width>785</width>
<height>580</height>
</size>
</property>
<property name="palette">
<palette>
<active>
@ -425,61 +447,13 @@
</disabled>
</palette>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>14</pointsize>
<italic>true</italic>
</font>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGraphicsView" name="graphics_view">
<property name="minimumSize">
<size>
<width>785</width>
<height>580</height>
</size>
</property>
<property name="autoFillBackground">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'dump_grabber.ui'
#
# Created: Wed Apr 16 22:18:59 2014
# Created: Tue May 13 06:55:09 2014
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!
@ -27,6 +27,19 @@ class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(811, 606)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Monospace"))
font.setPointSize(14)
font.setItalic(True)
MainWindow.setFont(font)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.graphics_view = QtGui.QGraphicsView(self.centralwidget)
self.graphics_view.setMinimumSize(QtCore.QSize(785, 580))
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -163,23 +176,11 @@ class Ui_MainWindow(object):
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipText, brush)
MainWindow.setPalette(palette)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.graphics_view = QtGui.QGraphicsView(self.centralwidget)
self.graphics_view.setMinimumSize(QtCore.QSize(785, 580))
self.graphics_view.setAutoFillBackground(True)
self.graphics_view.setPalette(palette)
self.graphics_view.setAutoFillBackground(False)
self.graphics_view.setObjectName(_fromUtf8("graphics_view"))
self.horizontalLayout.addWidget(self.graphics_view)
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout.addLayout(self.horizontalLayout)
spacerItem1 = QtGui.QSpacerItem(20, 4, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)

View File

@ -0,0 +1,9 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="icon" type="image/png" href="/icon.png" />
</head>
<body>
<img src="/texter_%d.mjpeg" alt="Smiley face" />
</body>
</html>

View File

@ -1,7 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of chaosc and psychosis
#
# chaosc is free software: you can redistribute it and/or modify
@ -21,297 +20,172 @@
from __future__ import absolute_import
import logging
import os
import os.path
import Queue
import re
import select
import socket
import signal
import sys
import threading
import time
from collections import deque
from datetime import datetime
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from chaosc.argparser_groups import *
from chaosc.argparser_groups import ArgParser
from chaosc.lib import logger, resolve_host
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from PyQt4.QtGui import QPixmap, QPainter
from PyQt4.QtNetwork import QHostAddress
from dump_grabber.dump_grabber_ui import Ui_MainWindow
from psylib.mjpeg_streaming_server import (MjpegStreamingServer,
MjpegStreamingConsumerInterface)
from psylib.psyqt_base import PsyQtChaoscClientBase
try:
from chaosc.c_osc_lib import OSCMessage, decode_osc
except ImportError as e:
except ImportError:
from chaosc.osc_lib import OSCMessage, decode_osc
app = QtGui.QApplication([])
QTAPP = QtGui.QApplication([])
class TextStorage(object):
def __init__(self, columns):
super(TextStorage, self).__init__()
self.column_count = columns
self.colors = (QtCore.Qt.red, QtCore.Qt.green, QtGui.QColor(46, 100, 254))
class ExclusiveTextStorage(object):
"""Stores the text representation of per actor osc messages"""
def init_columns(self):
raise NotImplementedError()
def add_text(self, column, text):
raise NotImplementedError()
class ColumnTextStorage(TextStorage):
def __init__(self, columns, default_font, column_width, line_height, scene):
super(ColumnTextStorage, self).__init__(columns)
self.columns = list()
self.column_count = columns
self.colors = (
QtCore.Qt.red, QtCore.Qt.green, QtGui.QColor(46, 100, 254))
self.lines = deque()
self.default_font = default_font
self.column_width = column_width
self.line_height = line_height
self.graphics_scene = scene
self.num_lines, self.offset = divmod(775, self.line_height)
def init_columns(self):
for x in range(self.column_count):
column = list()
color = self.colors[x]
for y in range(self.num_lines):
text_item = self.graphics_scene.addSimpleText("%d:%d" % (x, y), self.default_font)
text_item.setBrush(color)
text_item.setPos(x * self.column_width, y * self.line_height)
column.append(text_item)
self.columns.append(column)
def add_text(self, column, text):
text_item = self.graphics_scene.addSimpleText(text, self.default_font)
color = self.colors[column]
text_item.setBrush(color)
old_item = self.columns[column].pop(0)
self.graphics_scene.removeItem(old_item)
self.columns[column].append(text_item)
for iy, text_item in enumerate(self.columns[column]):
text_item.setPos(column * self.column_width, iy * self.line_height)
class ExclusiveTextStorage(TextStorage):
def __init__(self, columns, default_font, column_width, line_height, scene):
super(ExclusiveTextStorage, self).__init__(columns)
self.column_count = columns
self.lines = list()
self.default_font = default_font
self.column_width = column_width
self.line_height = line_height
self.graphics_scene = scene
self.num_lines, self.offset = divmod(775, self.line_height)
self.num_lines, self.offset = divmod(576, self.line_height)
self.data = deque()
def init_columns(self):
color = self.colors[0]
for y in range(self.num_lines):
for line_index in range(self.num_lines):
text_item = self.graphics_scene.addSimpleText("", self.default_font)
text_item.setBrush(color)
text_item.setPos(0, y * self.line_height)
text_item.setPos(0, line_index * self.line_height)
self.lines.append(text_item)
def add_text(self, column, text):
def __add_text(self, column, text):
text_item = self.graphics_scene.addSimpleText(text, self.default_font)
text_item.setX(column * self.column_width)
color = self.colors[column]
text_item.setBrush(color)
old_item = self.lines.pop(0)
text_item.setBrush(self.colors[column])
old_item = self.lines.popleft()
self.graphics_scene.removeItem(old_item)
self.lines.append(text_item)
for iy, text_item in enumerate(self.lines):
text_item.setY(iy * self.line_height)
def finish(self):
for column, text in self.data:
self.__add_text(column, text)
self.data.clear()
for text_index, text_item in enumerate(self.lines):
text_item.setY(text_index * self.line_height)
def add_text(self, column, text):
self.data.append((column, text))
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None, columns=3, column_exclusive=False):
super(MainWindow, self).__init__(parent)
class MainWindow(QtGui.QMainWindow, Ui_MainWindow,
MjpegStreamingConsumerInterface, PsyQtChaoscClientBase):
"""This app receives per actor osc messages and provides an mjpeg stream
with colored text representation arranged in columns"""
def __init__(self, args, parent=None):
self.args = args
super(MainWindow, self).__init__()
self.setupUi(self)
self.graphics_view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.graphics_view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.http_server = MjpegStreamingServer(
(args.http_host, args.http_port), self)
self.http_server.listen(port=args.http_port)
self.graphics_view.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.graphics_view.setVerticalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.graphics_view.setRenderHint(QtGui.QPainter.Antialiasing, True)
self.graphics_view.setFrameStyle(QtGui.QFrame.NoFrame)
self.graphics_scene = QtGui.QGraphicsScene(self)
self.graphics_scene.setSceneRect(0,0, 775, 580)
self.graphics_scene.setSceneRect(0, 0, 775, 580)
self.graphics_view.setScene(self.graphics_scene)
self.default_font = QtGui.QFont("Monospace", 14)
self.default_font.setStyleHint(QtGui.QFont.Monospace)
self.default_font.setBold(True)
self.graphics_scene.setFont(self.default_font)
self.font_metrics = QtGui.QFontMetrics(self.default_font)
self.line_height = self.font_metrics.height()
columns = 3
self.column_width = 775 / columns
self.text_storage = ExclusiveTextStorage(columns, self.default_font, self.column_width, self.line_height, self.graphics_scene)
#self.text_storage = ColumnTextStorage(columns, self.default_font, self.column_width, self.line_height, self.graphics_scene)
self.text_storage = ExclusiveTextStorage(columns, self.default_font,
self.column_width,
self.line_height,
self.graphics_scene)
self.text_storage.init_columns()
self.regex = re.compile("^/(uwe|merle|bjoern)/(.*?)$")
def pubdir(self):
return os.path.dirname(os.path.abspath(__file__))
def closeEvent(self, event):
msg = OSCMessage("/unsubscribe")
msg.appendTypedArg("localhost", "s")
msg.appendTypedArg(self.args.client_port, "i")
msg.appendTypedArg(self.args.authenticate, "s")
self.osc_sock.writeDatagram(
QByteArray(msg.encode_osc()), QHostAddress("127.0.0.1"), 7110)
def handle_osc_error(self, error):
logger.info("osc socket error %d", error)
def add_text(self, column, text):
self.text_storage.add_text(column, text)
def render(self):
image = QtGui.QImage(768, 576, QtGui.QImage.Format_ARGB32_Premultiplied)
def render_image(self):
self.text_storage.finish()
image = QPixmap(768, 576)
image.fill(QtCore.Qt.black)
painter = QtGui.QPainter(image)
painter.setRenderHints(QtGui.QPainter.RenderHint(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing), True)
painter = QPainter(image)
painter.setRenderHints(QPainter.RenderHint(
QPainter.Antialiasing | QPainter.TextAntialiasing), True)
painter.setFont(self.default_font)
self.graphics_view.render(painter, target=QtCore.QRectF(0,0,768,576),source=QtCore.QRect(0,0,768,576))
self.graphics_view.render(
painter, target=QtCore.QRectF(0, 0, 768, 576),
source=QtCore.QRect(0, 0, 768, 576))
painter.end()
return image
buf = QBuffer()
buf.open(QIODevice.WriteOnly)
image.save(buf, "JPG", 100)
image_data = buf.data()
return image_data
class OSCThread(threading.Thread):
def __init__(self, args):
super(OSCThread, self).__init__()
self.args = args
self.running = True
self.client_address = resolve_host(args.client_host, args.client_port, args.address_family)
self.chaosc_address = chaosc_host, chaosc_port = resolve_host(args.chaosc_host, args.chaosc_port, args.address_family)
self.osc_sock = socket.socket(args.address_family, 2, 17)
self.osc_sock.bind(self.client_address)
self.osc_sock.setblocking(0)
logger.info("starting up osc receiver on '%s:%d'", self.client_address[0], self.client_address[1])
self.subscribe_me()
def subscribe_me(self):
logger.info("%s: subscribing to '%s:%d' with label %r", datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1], self.args.subscriber_label)
msg = OSCMessage("/subscribe")
msg.appendTypedArg(self.client_address[0], "s")
msg.appendTypedArg(self.client_address[1], "i")
msg.appendTypedArg(self.args.authenticate, "s")
if self.args.subscriber_label is not None:
msg.appendTypedArg(self.args.subscriber_label, "s")
self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
def unsubscribe_me(self):
if self.args.keep_subscribed:
def got_message(self):
while self.osc_sock.hasPendingDatagrams():
data, address, port = self.osc_sock.readDatagram(
self.osc_sock.pendingDatagramSize())
try:
osc_address, typetags, args = decode_osc(data, 0, len(data))
except ValueError:
return
logger.info("unsubscribing from '%s:%d'", self.chaosc_address[0], self.chaosc_address[1])
msg = OSCMessage("/unsubscribe")
msg.appendTypedArg(self.client_address[0], "s")
msg.appendTypedArg(self.client_address[1], "i")
msg.appendTypedArg(self.args.authenticate, "s")
self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
def run(self):
while self.running:
try:
reads, writes, errs = select.select([self.osc_sock], [], [], 0.01)
except Exception, e:
pass
else:
if reads:
try:
osc_input, address = self.osc_sock.recvfrom(8192)
osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
queue.put_nowait((osc_address, messages))
except Exception, e:
pass
else:
pass
self.unsubscribe_me()
logger.info("OSCThread is going down")
queue = Queue.Queue()
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path))
if self.path=="" or self.path==None or self.path[:1]==".":
self.send_error(403,'Forbidden')
if self.path.endswith(".html"):
directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, self.path), "rb").read()
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(data)
elif self.path.endswith(".mjpeg"):
self.thread = thread = OSCThread(self.server.args)
thread.daemon = True
thread.start()
window = MainWindow()
window.hide()
self.send_response(200)
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=--aaboundary")
self.end_headers()
event_loop = QtCore.QEventLoop()
last_frame = time.time() - 1.
frame_rate = 16.0
frame_length = 1. / frame_rate
regex = re.compile("^/(uwe|merle|bjoern)/(.*?)$")
while 1:
event_loop.processEvents()
app.sendPostedEvents(None, 0)
while 1:
try:
osc_address, args = queue.get_nowait()
print osc_address
except Queue.Empty:
break
else:
try:
actor, text = regex.match(osc_address).groups()
if actor == "merle":
window.add_text(0, "%s = %s" % (text, ", ".join([str(i) for i in args])))
if actor == "uwe":
window.add_text(1, "%s = %s" % (text, ", ".join([str(i) for i in args])))
if actor == "bjoern":
window.add_text(2, "%s = %s" % (text, ", ".join([str(i) for i in args])))
actor, text = self.regex.match(osc_address).groups()
except AttributeError:
pass
now = time.time()
delta = now - last_frame
if delta > frame_length:
last_frame = now
img = window.render()
buffer = QBuffer()
buffer.open(QIODevice.WriteOnly)
img.save(buffer, "JPG")
JpegData = buffer.data()
self.wfile.write("--aaboundary\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(JpegData), JpegData))
JpegData = None
buffer = None
img = None
time.sleep(0.01)
return
except (KeyboardInterrupt, SystemError):
if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False
self.thread.join()
self.thread = None
except IOError, e:
if e[0] in (32, 104):
if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False
self.thread.join()
self.thread = None
else:
pass
class JustAHTTPServer(HTTPServer):
pass
if text == "temperatur":
text += "e"
if actor == "merle":
self.add_text(0, "%s = %s" % (
text, ", ".join([str(i) for i in args])))
elif actor == "uwe":
self.add_text(1, "%s = %s" % (
text, ", ".join([str(i) for i in args])))
elif actor == "bjoern":
self.add_text(2, "%s = %s" % (
text, ", ".join([str(i) for i in args])))
return True
def main():
@ -326,14 +200,16 @@ def main():
arg_parser.add_subscriber_group()
args = arg_parser.finalize()
http_host, http_port = resolve_host(args.http_host, args.http_port, args.address_family)
args.http_host, args.http_port = resolve_host(
args.http_host, args.http_port, args.address_family)
args.chaosc_host, args.chaosc_port = resolve_host(
args.chaosc_host, args.chaosc_port, args.address_family)
server = JustAHTTPServer((http_host, http_port), MyHandler)
server.address_family = args.address_family
server.args = args
logger.info("starting up http server on '%s:%d'", http_host, http_port)
window = MainWindow(args)
sys.excepthook = window.sigint_handler
signal.signal(signal.SIGTERM, window.sigterm_handler)
QTAPP.exec_()
server.serve_forever()
if ( __name__ == '__main__' ):
if __name__ == '__main__':
main()

View File

@ -1,9 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from distribute_setup import use_setuptools
use_setuptools()
import sys
from setuptools import find_packages, setup
@ -12,13 +9,15 @@ if sys.version_info >= (3,):
setup(
name='dump_grabber',
version="0.1",
version="0.2",
packages=find_packages(exclude=["scripts",]),
include_package_data = True,
exclude_package_data = {'': ['.gitignore']},
install_requires = ["psylib"],
# installing unzipped
zip_safe = False,

View File

@ -0,0 +1,556 @@
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import shutil
import sys
import time
import fnmatch
import tempfile
import tarfile
import optparse
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.49"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
# exitcode will be 2
return 2
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
# Setuptools 0.7b and later is a suitable (and preferable)
# substitute for any Distribute version.
try:
pkg_resources.require("setuptools>=0.7b")
return
except (pkg_resources.DistributionNotFound,
pkg_resources.VersionConflict):
pass
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>=" + version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
f = open(path)
existing_content = f.read()
f.close()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
f = open(path)
existing_content = f.read()
f.close()
return existing_content == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s to %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
log.warn('Creating %s', pkg_info)
try:
f = open(pkg_info, 'w')
except EnvironmentError:
log.warn("Don't have permissions to write %s, skipping", pkg_info)
return
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(
_create_fake_setuptools_pkg_info
)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install') + 1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index + 1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError:
# old distribute API
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools')
)
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patching complete.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
_cmd1 = ['-c', 'install', '--single-version-externally-managed']
_cmd2 = ['-c', 'install', '--record']
if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = []
if options.user_install:
if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
install_args.append('--user')
return install_args
def _parse_args():
"""
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
options = _parse_args()
tarball = download_setuptools(download_base=options.download_base)
return _install(tarball, _build_install_args(options))
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,7 +1,7 @@
<HTML>
<BODY>
<img src="/camera.mjpeg" alt="Smiley face">
<img src="/camera_%d.mjpeg" alt="Smiley face">
</BODY>
</HTML>

View File

@ -0,0 +1,282 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of psychose/ekgplotter package
#
# psychose/ekgplotter is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psychose/ekgplotter is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with psychose/ekgplotter. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import
import random
import os.path
import re
import signal
import sys
import exceptions
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QImage, QPixmap, QMainWindow
from PyQt4.QtCore import QBuffer, QIODevice
import numpy as np
import pyqtgraph as pg
from pyqtgraph.widgets.PlotWidget import PlotWidget
from pyqtgraph.graphicsItems.PlotCurveItem import PlotCurveItem
from pyqtgraph.graphicsItems.ScatterPlotItem import ScatterPlotItem
from chaosc.argparser_groups import ArgParser
from chaosc.lib import logger, resolve_host
from psylib.mjpeg_streaming_server import *
from psylib.psyqt_base import PsyQtChaoscClientBase
try:
from chaosc.c_osc_lib import decode_osc
except ImportError as e:
from chaosc.osc_lib import decode_osc
qtapp = QtGui.QApplication([])
def get_steps(pulse, delta_ms):
beat_length = 60000. / pulse
steps_pre = int(beat_length / delta_ms) + 1
used_sleep_time = beat_length / steps_pre
steps = int(beat_length / used_sleep_time)
return steps, used_sleep_time
class Generator(object):
def __init__(self, pulse=92, delta=80):
self.count = 0
self.pulse = random.randint(85, 105)
self.delta = delta
self.finished = False
self.steps, _ = get_steps(self.pulse, delta / 4)
def __call__(self):
while 1:
if self.count < int(self.steps / 100. * 30):
value = random.randint(30, 35)
elif self.count == int(self.steps / 100. * 30):
value = random.randint(55, 66)
elif self.count < int(self.steps / 100. * 45):
value = random.randint(30, 35)
elif self.count < int(self.steps / 2.):
value = random.randint(0, 15)
elif self.count == int(self.steps / 2.):
value = 255
elif self.count < int(self.steps / 100. * 60):
value = random.randint(25, 35)
elif self.count < int(self.steps / 100. * 70):
value = random.randint(10, 30)
elif self.count < self.steps:
value = random.randint(15, 30)
else:
self.finished = True
self.count = 0
value = 30
self.count += 1
yield value
def set_pulse(self, pulse):
self.pulse = pulse
self.steps, _ = get_steps(pulse, self.delta)
def retrigger(self):
self.count = self.steps / 2
class Actor(object):
def __init__(self, name, num_data, color, ix, max_actors, actor_height):
self.name = name
self.num_data = num_data
self.color = color
self.ix = ix
self.max_actors = max_actors
self.actor_height = actor_height
self.offset = ix * actor_height
self.data = np.array([self.offset + 30] * num_data)
self.head = 0
self.pre_head = 0
self.plotItem = PlotCurveItem(pen=pg.mkPen(color, width=3), width=4, name=name)
self.plotPoint = ScatterPlotItem(pen=pg.mkPen("w", width=5), brush=pg.mkBrush(color), size=5)
self.osci = None
self.osci_obj = None
self.render()
def __str__(self):
return "<Actor name:%r, position=%r>" % (self.name, self.head)
def __repr__(self):
return "Actor(%r, %r, %r, %r, %r, %r)" % (self.name, self.num_data,
self.color, self.ix, self.max_actors, self.actor_height)
def add_value(self, value):
self.pre_head = self.head
self.data[self.pre_head] = value / self.max_actors + self.offset
self.head = (self.pre_head + 1) % self.num_data
def fill_missing(self, count):
dp = self.head
for i in range(count):
self.data[dp] = self.offset
dp = (dp + 1) % self.num_data
self.pre_head = (dp - 1) % self.num_data
self.head = dp
def render(self):
self.plotItem.setData(y=self.data, clear=True)
self.plotPoint.setData(x=[self.pre_head], y=[self.data[self.pre_head]])
class PlotWindow(PlotWidget):
def __init__(self, title=None, **kargs):
self.win = QtGui.QMainWindow()
self.win.resize(768, 576)
PlotWidget.__init__(self, **kargs)
self.win.setCentralWidget(self)
for m in ['resize']:
setattr(self, m, getattr(self.win, m))
if title is not None:
self.win.setWindowTitle(title)
self.win.show()
class EkgPlotWidget(QMainWindow, PsyQtChaoscClientBase, MjpegStreamingConsumerInterface):
def __init__(self, args, parent=None):
self.args = args
super(EkgPlotWidget, self).__init__()
PsyQtChaoscClientBase.__init__(self)
self.plot_widget = PlotWidget(title="Psychose - EkgPlotter")
colors = ["r", "g", "b"]
self.active_actors = list()
self.actors = dict()
self.max_value = 255
actor_names = ["merle", "uwe", "bjoern"]
self.max_actors = len(actor_names)
self.actor_height = self.max_value / self.max_actors
self.fps = 12.5
self.http_server = MjpegStreamingServer((args.http_host, args.http_port), self, self.fps)
self.http_server.listen(port=args.http_port)
self.num_data = 100
self.plot_widget.showGrid(False, False)
self.plot_widget.setYRange(0, 255)
self.plot_widget.setXRange(0, self.num_data)
self.plot_widget.resize(768, 576)
bottom_axis = self.plot_widget.getAxis("bottom")
left_axis = self.plot_widget.getAxis("left")
bottom_axis.setTicks([])
left_axis.setTicks([])
bottom_axis.hide()
left_axis.hide()
for ix, (actor_name, color) in enumerate(zip(actor_names, colors)):
self.add_actor(actor_name, self.num_data, color, ix, self.max_actors, self.actor_height)
self.set_positions()
self.heartbeat_regex = re.compile("^/(.*?)/heartbeat$")
def pubdir(self):
return os.path.dirname(os.path.abspath(__file__))
def add_actor(self, actor_name, num_data, color, ix, max_actors, actor_height):
actor_obj = Actor(actor_name, num_data, color, ix, max_actors, actor_height)
self.actors[actor_name] = actor_obj
self.plot_widget.addItem(actor_obj.plotItem)
self.plot_widget.addItem(actor_obj.plotPoint)
self.active_actors.append(actor_obj)
actor_obj.osci_obj = Generator(pulse=random.randint(88, 104), delta=self.http_server.timer_delta)
actor_obj.osci = actor_obj.osci_obj()
def set_positions(self):
for ix, actor_obj in enumerate(self.active_actors):
actor_obj.plotItem.setPos(0, ix * 2)
actor_obj.plotPoint.setPos(0, ix * 2)
def active_actor_count(self):
return self.max_actors
def update(self, osc_address, args):
res = self.heartbeat_regex.match(osc_address)
if res:
actor_name = res.group(1)
actor_obj = self.actors[actor_name]
#logger.info("actor: %r, %r", actor_name, args)
if args[0] == 1:
actor_obj.osci_obj.retrigger()
actor_obj.osci_obj.set_pulse(args[1])
def render_image(self):
for actor_obj in self.active_actors:
actor_obj.add_value(actor_obj.osci.next())
actor_obj.add_value(actor_obj.osci.next())
actor_obj.add_value(actor_obj.osci.next())
actor_obj.add_value(actor_obj.osci.next())
actor_obj.render()
image = QPixmap(768, 576)
image.fill(QtCore.Qt.white)
painter = QtGui.QPainter(image)
painter.setRenderHints(QtGui.QPainter.RenderHint(
QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing),
True)
scene = self.plot_widget.plotItem.scene()
scene.render(painter, QtCore.QRectF(0, 0, 768, 576), QtCore.QRectF(0, 0, 768, 576))
painter.end()
buf = QBuffer()
buf.open(QIODevice.WriteOnly)
image.save(buf, "JPG", 80)
JpegData = buf.data()
return JpegData
def got_message(self):
while self.osc_sock.hasPendingDatagrams():
data, address, port = self.osc_sock.readDatagram(self.osc_sock.pendingDatagramSize())
try:
osc_address, typetags, args = decode_osc(data, 0, len(data))
except ValueError, error:
logger.exception(error)
else:
self.update(osc_address, args)
def main():
arg_parser = ArgParser("ekgplotter")
arg_parser.add_global_group()
client_group = arg_parser.add_client_group()
arg_parser.add_argument(client_group, '-x', "--http_host", default='::',
help='my host, defaults to "::"')
arg_parser.add_argument(client_group, '-X', '--http_port', default=9000,
type=int, help='my port, defaults to 9000')
arg_parser.add_chaosc_group()
arg_parser.add_subscriber_group()
args = arg_parser.finalize()
args.http_host, args.http_port = resolve_host(args.http_host, args.http_port, args.address_family)
args.chaosc_host, args.chaosc_port = resolve_host(args.chaosc_host, args.chaosc_port, args.address_family)
window = EkgPlotWidget(args)
logger.info("foooooooo")
window.hide()
#sys.excepthook = window.sigint_handler
#signal.signal(signal.SIGTERM, window.sigterm_handler)
qtapp.exec_()
if __name__ == '__main__':
main()

View File

@ -1,9 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from distribute_setup import use_setuptools
use_setuptools()
import sys
from setuptools import find_packages, setup
@ -12,7 +9,7 @@ if sys.version_info >= (3,):
setup(
name='ekgplotter',
version="0.1",
version="0.2",
packages=find_packages(exclude=["scripts",]),
include_package_data = True,
@ -22,7 +19,7 @@ setup(
exclude_package_data = {'': ['.gitignore']},
install_requires=["pyqtgraph"],
install_requires=["psylib", "pyqtgraph"],
# installing unzipped
zip_safe = False,
@ -30,7 +27,7 @@ setup(
# predefined extension points, e.g. for plugins
entry_points = """
[console_scripts]
ekgplotter = ekgplotter.main:main
ekgplotter = ekgplotter.main_qt:main
""",
# pypi metadata
author = "Stefan Kögl",

556
psylib/distribute_setup.py Normal file
View File

@ -0,0 +1,556 @@
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import shutil
import sys
import time
import fnmatch
import tempfile
import tarfile
import optparse
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.49"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
# exitcode will be 2
return 2
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
# Setuptools 0.7b and later is a suitable (and preferable)
# substitute for any Distribute version.
try:
pkg_resources.require("setuptools>=0.7b")
return
except (pkg_resources.DistributionNotFound,
pkg_resources.VersionConflict):
pass
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>=" + version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
f = open(path)
existing_content = f.read()
f.close()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
f = open(path)
existing_content = f.read()
f.close()
return existing_content == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s to %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
log.warn('Creating %s', pkg_info)
try:
f = open(pkg_info, 'w')
except EnvironmentError:
log.warn("Don't have permissions to write %s, skipping", pkg_info)
return
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(
_create_fake_setuptools_pkg_info
)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install') + 1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index + 1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError:
# old distribute API
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools')
)
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patching complete.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
_cmd1 = ['-c', 'install', '--single-version-externally-managed']
_cmd2 = ['-c', 'install', '--record']
if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = []
if options.user_install:
if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
install_args.append('--user')
return install_args
def _parse_args():
"""
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
options = _parse_args()
tarball = download_setuptools(download_base=options.download_base)
return _install(tarball, _build_install_args(options))
if __name__ == '__main__':
sys.exit(main())

View File

View File

@ -0,0 +1,232 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of chaosc/psylib package
#
# chaosc/psylib is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# chaosc/psylib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with chaosc/psylib. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import
import os
import os.path
import re
from chaosc.lib import logger
from PyQt4 import QtCore
from PyQt4.QtCore import QByteArray
from PyQt4.QtNetwork import QTcpServer, QTcpSocket
__all__ = ["MjpegStreamingConsumerInterface", "MjpegStreamingServer"]
class MjpegStreamingConsumerInterface(object):
def pubdir(self):
""" returns the directory, from where your static files should be served
fast and dirty implementation e.g:
return os.path.dirname(os.path.abspath(__file__))
"""
raise NotImplementedError()
def render_image(self):
"""returns a QByteArray with the binary date of a jpg image
this method should implement the actual window/widget grabbing"""
raise NotImplementedError()
class MjpegStreamingServer(QTcpServer):
"""A simple async http class which provides a mjpeg stream and if found,
an index.html file containing the mjpeg stream.
Parent should implement the interface 'MjpegStreamingConsumerInterface'
"""
def __init__(self, server_address, parent=None, fps=12.5):
super(MjpegStreamingServer, self).__init__(parent)
self.server_address = server_address
self.newConnection.connect(self.new_connection)
assert isinstance(parent, MjpegStreamingConsumerInterface)
self.widget = parent
self.sockets = list()
self.img_data = None
self.fps = fps
self.timer_delta = 1000 / fps
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.send_image)
self.timer.start(self.timer_delta)
self.stream_clients = list()
self.get_regex = re.compile("^GET /(\w+?)\.(\w+?) HTTP/(\d+\.\d+)$")
self.host_regex = re.compile("^Host: (\w+?):(\d+)$")
self.html_map = dict()
def handle_request(self):
sock = self.sender()
sock_id = id(sock)
logger.info("handle_request: sock_id=%r", sock_id)
if sock.state() in (
QTcpSocket.UnconnectedState, QTcpSocket.ClosingState):
logger.info("connection closed")
self.sockets.remove(sock)
sock.deleteLater()
return
client_data = str(sock.readAll())
logger.info("request %r", client_data)
line = client_data.split("\r\n")[0]
logger.info("first line: %r", line)
try:
resource, ext, http_version = self.get_regex.match(line).groups()
logger.info(
"resource=%r, ext=%r, http_version=%r",
resource, ext, http_version)
except AttributeError:
try:
host, port = self.host_regex.match(line).groups()
logger.info("found host header %r %r", host, port)
#return
#sock.write("HTTP/1.1 501 Not Implemented\r\n")
return
except AttributeError:
logger.info("no matching request - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
return
else:
if ext == "ico":
directory = self.widget.pubdir()
try:
data = open(
os.path.join(directory, "favicon.ico"), "rb").read()
except IOError:
logger.error(
"request not found/handled - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
return
else:
sock.write(QByteArray('HTTP/1.1 200 Ok\r\nContent-Type:' \
'image/x-ico\r\n\r\n%s' % data))
elif ext == "html":
directory = self.widget.pubdir()
try:
data = open(os.path.join(
directory, "index.html"), "rb").read() % sock_id
self.html_map[sock_id] = None
except IOError:
logger.error(
"request not found/handled - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
return
else:
sock.write(QByteArray('HTTP/1.1 200 Ok\r\nContent-Type:"\
"text/html;encoding: utf-8\r\n\r\n%s' % data))
elif ext == "mjpeg":
try:
_, html_sock_id = resource.split("_", 1)
html_sock_id = int(html_sock_id)
except ValueError:
html_sock_id = None
if sock not in self.stream_clients:
logger.info("starting streaming...")
if html_sock_id is not None:
self.html_map[html_sock_id] = sock
self.stream_clients.append(sock)
sock.write(QByteArray('HTTP/1.1 200 Ok\r\n" \
"Content-Type: multipart/x-mixed-replace;" \
"boundary=--2342\r\n\r\n'))
else:
logger.error(
"request not found/handled - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
def slot_remove_connection(self):
try:
sock = self.sender()
except RuntimeError:
return
if sock.state() == QTcpSocket.UnconnectedState:
self.__remove_connection(sock)
def __remove_connection(self, sock):
sock_id = id(sock)
sock.disconnected.disconnect(self.slot_remove_connection)
sock.close()
sock.deleteLater()
try:
self.sockets.remove(sock)
logger.info("connection %r removed", sock_id)
except ValueError, msg:
logger.info("connection %r was not stored?", sock_id)
try:
self.stream_clients.remove(sock)
except ValueError:
logger.info("connection %r was not streaming", sock_id)
# cleaning up streaming connections if that sock is serving index.html
try:
stream_client = self.html_map.pop(sock_id)
except KeyError:
logger.info("connection %r has no child connections", sock_id)
else:
try:
stream_client.close()
stream_client.deleteLater()
except AttributeError, msg:
logger.info("no stream client")
else:
try:
self.stream_clients.remove(stream_client)
logger.info("child connection %r removed from streaming",
id(stream_client))
except ValueError:
pass
try:
self.sockets.remove(stream_client)
logger.info("child connection %r removed from storage",
id(stream_client))
except ValueError:
pass
def send_image(self):
if not self.stream_clients:
return
img_data = self.widget.render_image()
len_data = len(img_data)
array = QByteArray("--2342\r\nContent-Type: image/jpeg\r\n" \
"Content-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len_data, img_data))
for sock in self.stream_clients:
sock.write(array)
def new_connection(self):
while self.hasPendingConnections():
sock = self.nextPendingConnection()
logger.info("new connection=%r", id(sock))
sock.readyRead.connect(self.handle_request)
sock.disconnected.connect(self.slot_remove_connection)
self.sockets.append(sock)
def stop(self):
self.stream_clients = list()
for sock in self.sockets:
sock.close()
sock.deleteLater()
self.sockets = list()
self.html_map = dict()
self.close()

164
psylib/psylib/other.py Normal file
View File

@ -0,0 +1,164 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of chaosc and psychosis
#
# chaosc/psychosis is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# chaosc/psychosis is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with chaosc/psychosis. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import
import os
import os.path
import re
import sys
from datetime import datetime
from chaosc.argparser_groups import *
from chaosc.lib import logger, resolve_host
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from PyQt4.QtNetwork import QTcpServer
class MjpegStreamingServer(QTcpServer):
def __init__(self, server_address, parent=None):
super(MjpegStreamingServer, self).__init__(parent)
self.server_address = server_address
self.newConnection.connect(self.new_connection)
self.widget = parent
self.win_id = self.widget.winId()
self.sockets = list()
self.img_data = None
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.render_image)
self.timer.start(80)
self.stream_clients = list()
self.get_regex = re.compile("^GET /(\w+?)\.(\w+?) HTTP/(\d+\.\d+)$")
self.host_regex = re.compile("^Host: (\w+?):(\d+)$")
self.html_map = dict()
def handle_request(self):
sock = self.sender()
logger.info("handle_request: %s %d", sock.peerAddress(), sock.peerPort())
sock_id = id(sock)
if sock.state() in (QTcpSocket.UnconnectedState, QTcpSocket.ClosingState):
logger.info("connection closed")
self.sockets.remove(sock)
sock.deleteLater()
return
client_data = str(sock.readAll())
logger.info("request %r", client_data)
line = client_data.split("\r\n")[0]
logger.info("first line: %r", line)
try:
resource, ext, http_version = self.get_regex.match(line).groups()
logger.info("resource=%r, ext=%r, http_version=%r", resource, ext, http_version)
except AttributeError:
try:
host, port = self.host_regex.match(line).groups()
print "found host header", host, port
return
#sock.write("HTTP/1.1 501 Not Implemented\r\n")
except AttributeError:
logger.info("no matching request - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
return
else:
if ext == "ico":
directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, "favicon.ico"), "rb").read()
sock.write(QByteArray('HTTP/1.1 200 Ok\r\nContent-Type: image/x-ico\r\n\r\n%s' % data))
elif ext == "html":
directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, "index.html"), "rb").read() % sock_id
self.html_map[sock_id] = None
sock.write(QByteArray('HTTP/1.1 200 Ok\r\nContent-Type: text/html;encoding: utf-8\r\n\r\n%s' % data))
elif ext == "mjpeg":
try:
_, html_sock_id = resource.split("_", 1)
html_sock_id = int(html_sock_id)
except ValueError:
html_sock_id = None
if sock not in self.stream_clients:
logger.info("starting streaming...")
if html_sock_id is not None:
self.html_map[html_sock_id] = sock
self.stream_clients.append(sock)
sock.write(QByteArray('HTTP/1.1 200 Ok\r\nContent-Type: multipart/x-mixed-replace; boundary=--2342\r\n\r\n'))
else:
logger.error("request not found/handled - sending 404 not found")
sock.write("HTTP/1.1 404 Not Found\r\n")
def remove_connection(self):
try:
sock = self.sender()
except RuntimeError:
return
sock_id = id(sock)
logger.info("remove_connection: sock=%r, sock_id=%r", sock, sock_id)
if sock.state() == QTcpSocket.UnconnectedState:
sock.disconnected.disconnect(self.remove_connection)
self.sockets.remove(sock)
logger.info("removed sock_id=%r", sock_id)
sock.close()
try:
self.stream_clients.remove(sock)
except ValueError:
pass
try:
stream_client = self.html_map.pop(sock_id)
except KeyError:
logger.info("socket has no child socket")
else:
stream_client.close()
try:
self.stream_clients.remove(stream_client)
logger.info("removed stream_client=%r", id(stream_client))
except ValueError:
pass
try:
self.sockets.remove(stream_client)
logger.info("removed child sock_id=%r", id(stream_client))
except ValueError:
pass
def render_image(self):
if not self.stream_clients:
return
img_data = self.widget.render_image()
len_data = len(img_data)
array = QByteArray("--2342\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len_data, img_data))
for sock in self.stream_clients:
sock.write(array)
def new_connection(self):
while self.hasPendingConnections():
sock = self.nextPendingConnection()
logger.info("new connection=%r", id(sock))
sock.readyRead.connect(self.handle_request)
sock.disconnected.connect(self.remove_connection)
self.sockets.append(sock)
def stop(self):
self.stream_clients = list()
self.sockets = list()
self.html_map = dict()
self.close()

108
psylib/psylib/psyqt_base.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of chaosc/psylib package
#
# chaosc/psylib is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# chaosc/psylib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with chaosc/psylib. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import
import sys
import traceback
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray
from PyQt4.QtNetwork import QUdpSocket, QHostAddress
from chaosc.lib import logger
try:
from chaosc.c_osc_lib import OSCMessage, decode_osc
except ImportError as e:
from chaosc.osc_lib import OSCMessage, decode_osc
class PsyQtClientBase(QtCore.QObject):
def __init__(self):
super(PsyQtClientBase, self).__init__()
# periodically trap into python interpreter domain to catch signals etc
timer = QtCore.QTimer()
timer.start(2000)
timer.timeout.connect(lambda: None)
def sigint_handler(self, ex_cls, ex, traceback):
"""Handler for the SIGINT signal."""
if ex_cls == KeyboardInterrupt:
logger.info("found KeyboardInterrupt")
QtGui.QApplication.exit()
else:
logger.critical(''.join(traceback.format_tb(tb)))
logger.critical('{0}: {1}'.format(ex_cls, ex))
class PsyQtChaoscClientBase(PsyQtClientBase):
def __init__(self):
super(PsyQtChaoscClientBase, self).__init__()
self.osc_sock = QUdpSocket(self)
logger.info("osc bind localhost %d", self.args.client_port)
self.osc_sock.bind(QHostAddress(self.args.client_host), self.args.client_port)
self.osc_sock.readyRead.connect(self.got_message)
self.osc_sock.error.connect(self.handle_osc_error)
self.subscribe()
def sigint_handler(self, ex_cls, ex, tb):
"""Handler for the SIGINT signal."""
logger.info("sigint_handler")
if ex_cls == KeyboardInterrupt:
logger.info("found KeyboardInterrupt")
self.unsubscribe()
QtGui.QApplication.exit()
else:
logger.critical(''.join(traceback.format_tb(tb)))
logger.critical('{0}: {1}'.format(ex_cls, ex))
def sigterm_handler(self, *args):
logger.info("sigterm_handler")
self.unsubscribe()
QtGui.QApplication.exit()
def subscribe(self):
logger.info("subscribe")
msg = OSCMessage("/subscribe")
msg.appendTypedArg("localhost", "s")
msg.appendTypedArg(self.args.client_port, "i")
msg.appendTypedArg(self.args.authenticate, "s")
if self.args.subscriber_label is not None:
msg.appendTypedArg(self.args.subscriber_label, "s")
self.osc_sock.writeDatagram(QByteArray(msg.encode_osc()), QHostAddress(self.args.chaosc_host), self.args.chaosc_port)
def unsubscribe(self):
logger.info("unsubscribe")
msg = OSCMessage("/unsubscribe")
msg.appendTypedArg("localhost", "s")
msg.appendTypedArg(self.args.client_port, "i")
msg.appendTypedArg(self.args.authenticate, "s")
self.osc_sock.writeDatagram(QByteArray(msg.encode_osc()), QHostAddress(self.args.chaosc_host), self.args.chaosc_port)
def handle_osc_error(self, error):
logger.info("osc socket error %d", error)
def closeEvent(self, event):
logger.info("closeEvent", event)
self.unsubscribe()
event.accept()

40
psylib/setup.py Normal file
View File

@ -0,0 +1,40 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from setuptools import find_packages, setup
if sys.version_info >= (3,):
extras['use_2to3'] = True
setup(
name='psylib',
version="0.2",
packages=find_packages(exclude=["scripts",]),
include_package_data = True,
exclude_package_data = {'': ['.gitignore']},
zip_safe = False,
# pypi metadata
author = "Stefan Kögl",
# FIXME: add author email
author_email = "hotte@ctdo.de",
description = "library for psychosis",
# FIXME: add long_description
long_description = """
""",
# FIXME: add license
license = "GPL",
# FIXME: add keywords
keywords = "",
# FIXME: add download url
url = "",
)

View File

@ -0,0 +1,556 @@
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import shutil
import sys
import time
import fnmatch
import tempfile
import tarfile
import optparse
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.49"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
# exitcode will be 2
return 2
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
# Setuptools 0.7b and later is a suitable (and preferable)
# substitute for any Distribute version.
try:
pkg_resources.require("setuptools>=0.7b")
return
except (pkg_resources.DistributionNotFound,
pkg_resources.VersionConflict):
pass
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>=" + version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
f = open(path)
existing_content = f.read()
f.close()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
f = open(path)
existing_content = f.read()
f.close()
return existing_content == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s to %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
log.warn('Creating %s', pkg_info)
try:
f = open(pkg_info, 'w')
except EnvironmentError:
log.warn("Don't have permissions to write %s, skipping", pkg_info)
return
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(
_create_fake_setuptools_pkg_info
)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install') + 1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index + 1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError:
# old distribute API
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools')
)
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patching complete.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
_cmd1 = ['-c', 'install', '--single-version-externally-managed']
_cmd2 = ['-c', 'install', '--record']
if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = []
if options.user_install:
if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
install_args.append('--user')
return install_args
def _parse_args():
"""
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
options = _parse_args()
tarball = download_setuptools(download_base=options.download_base)
return _install(tarball, _build_install_args(options))
if __name__ == '__main__':
sys.exit(main())

View File

@ -28,6 +28,7 @@ import time
import sys
from chaosc.argparser_groups import ArgParser
from chaosc.lib import logger
try:
@ -47,8 +48,8 @@ class Platform(object):
def connect(self):
print "connect serial"
print "waiting for the device %r to come up" % self.args.device
logger.info("connect serial")
logger.info("waiting for the device %r to come up", self.args.device)
self.serial_sock = serial.Serial()
self.serial_sock.port = self.args.device
self.serial_sock.baudrate = 115200
@ -57,7 +58,7 @@ class Platform(object):
try:
self.serial_sock.open()
except (serial.serialutil.SerialException, os.error), e:
print "serial error", e
logger.exception(e)
time.sleep(0.5)
pass
else:
@ -66,12 +67,12 @@ class Platform(object):
def close(self):
if self.serial_sock is not None:
print "close serial"
logger.info("close serial")
self.serial_sock.close()
def reconnect(self):
print "reconnect serial"
logger.info("reconnect serial")
self.close()
self.connect()

View File

@ -39,20 +39,19 @@ def main():
#print repr(data)
except (socket.error, serial.serialutil.SerialException), msg:
# got disconnected?
print "serial socket error!!!", msg
logger.exception(msg)
platform.reconnect()
print "data", repr(data)
try:
airFlow, emg, temp = data.split(";")
except ValueError, e:
print e
except ValueError, msg:
logger.exception(msg)
continue
try:
airFlow = int(airFlow)
except ValueError, e:
print e
except ValueError, msg:
logger.exception(msg)
continue
try:
@ -60,14 +59,14 @@ def main():
osc_message.appendTypedArg(airFlow, "i")
platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg:
print "cannot connect to chaosc", msg
logger.exception(msg)
continue
try:
emg = int(emg)
except ValueError, e:
print e
except ValueError, msg:
logger.exception(msg)
continue
try:
@ -75,14 +74,14 @@ def main():
osc_message.appendTypedArg(emg, "i")
platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg:
print "cannot connect to chaosc", msg
logger.exception(msg)
continue
try:
temp = int(temp)
except ValueError, e:
print e
except ValueError, msg:
logger.exception(msg)
continue
try:
@ -90,7 +89,7 @@ def main():
osc_message.appendTypedArg(temp, "i")
platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg:
print "cannot connect to chaosc", msg
logger.exception(msg)
continue

View File

@ -51,11 +51,11 @@ def main():
except TypeError, e:
continue
if msg_count >= 20:
logger.info("value = %d", t)
msg_count = 0
else:
msg_count += 1
#if msg_count >= 20:
# logger.info("value = %d", t)
# msg_count = 0
#else:
# msg_count += 1
try:
osc_message = OSCMessage("/%s/ekg" % actor)

View File

@ -29,7 +29,6 @@ import datetime
try:
from chaosc.c_osc_lib import OSCMessage
except ImportError as e:
print(e)
from chaosc.osc_lib import OSCMessage
@ -48,7 +47,7 @@ class Forwarder(object):
def close(self):
"""Close all resources and unpublish service"""
print "%s: closing..." % (self.device, )
logger.info("%s: closing...", self.device)
self.serial.close()
@ -58,7 +57,6 @@ class EHealth2OSC(Forwarder):
def handle_read(self, osc_sock):
data = self.serial.readline()[:-2]
print repr(data)
try:
airFlow, emg, temp = data.split(";")
except ValueError:
@ -106,7 +104,7 @@ class RingBuffer(object):
self.head = (self.head + 1) % self.length
def getData(self):
print "getData", self.ring_buf, self.head
#print "getData", self.ring_buf, self.head
data = list()
for i in range(7, 1, -1):
value = self.ring_buf[(self.head - i) % self.length]
@ -146,7 +144,7 @@ class Pulse2OSC(Forwarder):
osc_message.appendTypedArg(heart_rate, "i")
osc_message.appendTypedArg(o2, "i")
osc_sock.sendall(osc_message.encode_osc())
print "heartbeat", datetime.datetime.now(), heart_signal
#print "heartbeat", datetime.datetime.now(), heart_signal
self.heartbeat_on = True
elif pulse == 1 and self.heartbeat_on:
#print "off heartbeat", datetime.datetime.now(), heart_signal

View File

@ -41,7 +41,7 @@ class RingBuffer(object):
self.head = (self.head + 1) % self.length
def getData(self):
print "getData", self.ring_buf, self.head
#print "getData", self.ring_buf, self.head
data = list()
for i in range(self.length + 1, 1, -1):
value = self.ring_buf[(self.head - i) % self.length]
@ -52,7 +52,7 @@ class RingBuffer(object):
raise ValueError("not complete - reset ringbuffer")
data.append(value)
if data[0] != 0x0 or data[1] != 0xff:
print "issue", data
#print "issue", data
self.reset()
self.ring_buf[0] = 0
self.head = 1
@ -77,7 +77,7 @@ def main():
continue
except (socket.error, serial.serialutil.SerialException), msg:
# got disconnected?
print "serial socket error!!!", msg
logger.exception(msg)
platform.reconnect()
try:
@ -91,8 +91,8 @@ def main():
if t == 0:
try:
heart_signal, heart_rate, o2, pulse = buf.getData()
except ValueError, e:
print e
except ValueError, msg:
logger.exception(msg)
continue
if pulse == 245 and not heartbeat_on:
@ -103,12 +103,12 @@ def main():
osc_message.appendTypedArg(heart_rate, "i")
osc_message.appendTypedArg(o2, "i")
platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
print "on heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse
#print "on heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse
except socket.error, msg:
print "cannot connect to chaosc"
logger.exception(msg)
continue
elif pulse == 1 and heartbeat_on:
print "off heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse
#print "off heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse
heartbeat_on = False
try:
osc_message = OSCMessage("/%s/heartbeat" % actor)
@ -117,7 +117,7 @@ def main():
osc_message.appendTypedArg(o2, "i")
platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg:
print "cannot connect to chaosc"
logger.exception(msg)
continue

556
texter/distribute_setup.py Normal file
View File

@ -0,0 +1,556 @@
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import shutil
import sys
import time
import fnmatch
import tempfile
import tarfile
import optparse
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.49"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
# exitcode will be 2
return 2
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
shutil.rmtree(tmpdir)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
# Setuptools 0.7b and later is a suitable (and preferable)
# substitute for any Distribute version.
try:
pkg_resources.require("setuptools>=0.7b")
return
except (pkg_resources.DistributionNotFound,
pkg_resources.VersionConflict):
pass
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>=" + version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
f = open(path)
existing_content = f.read()
f.close()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
f = open(path)
existing_content = f.read()
f.close()
return existing_content == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s to %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
log.warn('Creating %s', pkg_info)
try:
f = open(pkg_info, 'w')
except EnvironmentError:
log.warn("Don't have permissions to write %s, skipping", pkg_info)
return
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(
_create_fake_setuptools_pkg_info
)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install') + 1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index + 1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError:
# old distribute API
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools')
)
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patching complete.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
_cmd1 = ['-c', 'install', '--single-version-externally-managed']
_cmd2 = ['-c', 'install', '--record']
if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = []
if options.user_install:
if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
install_args.append('--user')
return install_args
def _parse_args():
"""
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
options = _parse_args()
tarball = download_setuptools(download_base=options.download_base)
return _install(tarball, _build_install_args(options))
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,9 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from distribute_setup import use_setuptools
use_setuptools()
import sys
from setuptools import find_packages, setup
@ -12,13 +9,15 @@ if sys.version_info >= (3,):
setup(
name='texter',
version="0.1",
version="0.2",
packages=find_packages(exclude=["scripts",]),
include_package_data = True,
install_requires = ["psylib"],
package_data = {
"texter" : ["*.ui", "*.qrc", "*.png"]},
"texter" : ["*.ui", "*.qrc", "*.png", "*.ico", "*.html"]},
exclude_package_data = {'': ['.gitignore']},
@ -47,7 +46,7 @@ setup(
""",
# FIXME: add license
license = "LGPL",
license = "GPL",
# FIXME: add keywords
keywords = "",

Binary file not shown.

View File

@ -1,2 +1,2 @@
pyuic4 -o texter_ui.py texter3.ui
pyuic4 -o text_sorter_ui.py texter4.ui
# pyuic4 -o texter_ui.py texter.ui
pyuic4 -o edit_dialog_ui.py edit_dialog.ui

View File

@ -0,0 +1,507 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditDialog</class>
<widget class="QWidget" name="EditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1084</width>
<height>633</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QListView" name="text_list"/>
</item>
<item>
<widget class="QTextEdit" name="text_preview">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="KButtonGroup" name="kbuttongroup">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KArrowButton" name="move_down_button">
<property name="arrowType" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item>
<widget class="KArrowButton" name="move_up_button"/>
</item>
<item>
<widget class="KPushButton" name="remove_button">
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset theme="edit-delete">
<normaloff>../../../../</normaloff>../../../../</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KArrowButton</class>
<extends>QPushButton</extends>
<header>karrowbutton.h</header>
</customwidget>
<customwidget>
<class>KButtonGroup</class>
<extends>QGroupBox</extends>
<header>kbuttongroup.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KPushButton</class>
<extends>QPushButton</extends>
<header>kpushbutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'texter4.ui'
# Form implementation generated from reading ui file 'edit_dialog.ui'
#
# Created: Mon Apr 28 21:58:51 2014
# Created: Tue May 27 18:18:57 2014
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!
@ -23,32 +23,23 @@ except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_TextSorterDialog(object):
def setupUi(self, TextSorterDialog):
TextSorterDialog.setObjectName(_fromUtf8("TextSorterDialog"))
TextSorterDialog.resize(1084, 633)
self.verticalLayout = QtGui.QVBoxLayout(TextSorterDialog)
class Ui_EditDialog(object):
def setupUi(self, EditDialog):
EditDialog.setObjectName(_fromUtf8("EditDialog"))
EditDialog.resize(1084, 633)
self.verticalLayout = QtGui.QVBoxLayout(EditDialog)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.splitter = QtGui.QSplitter(TextSorterDialog)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName(_fromUtf8("splitter"))
self.text_list = QtGui.QListView(self.splitter)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(1)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.text_list.sizePolicy().hasHeightForWidth())
self.text_list.setSizePolicy(sizePolicy)
self.text_list.setMinimumSize(QtCore.QSize(200, 576))
self.text_list.setMaximumSize(QtCore.QSize(16777215, 576))
self.horizontalLayout_2 = QtGui.QHBoxLayout()
self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
self.text_list = QtGui.QListView(EditDialog)
self.text_list.setObjectName(_fromUtf8("text_list"))
self.text_preview = KRichTextWidget(self.splitter)
self.horizontalLayout_2.addWidget(self.text_list)
self.text_preview = QtGui.QTextEdit(EditDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(100)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.text_preview.sizePolicy().hasHeightForWidth())
self.text_preview.setSizePolicy(sizePolicy)
self.text_preview.setMinimumSize(QtCore.QSize(0, 576))
self.text_preview.setMaximumSize(QtCore.QSize(768, 576))
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -186,10 +177,13 @@ class Ui_TextSorterDialog(object):
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipText, brush)
self.text_preview.setPalette(palette)
self.text_preview.setUndoRedoEnabled(False)
self.text_preview.setReadOnly(True)
self.text_preview.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
self.text_preview.setObjectName(_fromUtf8("text_preview"))
self.verticalLayout.addWidget(self.splitter)
self.kbuttongroup = KButtonGroup(TextSorterDialog)
self.horizontalLayout_2.addWidget(self.text_preview)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.kbuttongroup = KButtonGroup(EditDialog)
self.kbuttongroup.setObjectName(_fromUtf8("kbuttongroup"))
self.horizontalLayout = QtGui.QHBoxLayout(self.kbuttongroup)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
@ -206,14 +200,12 @@ class Ui_TextSorterDialog(object):
self.remove_button.setObjectName(_fromUtf8("remove_button"))
self.horizontalLayout.addWidget(self.remove_button)
self.verticalLayout.addWidget(self.kbuttongroup)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.retranslateUi(TextSorterDialog)
QtCore.QMetaObject.connectSlotsByName(TextSorterDialog)
self.retranslateUi(EditDialog)
QtCore.QMetaObject.connectSlotsByName(EditDialog)
def retranslateUi(self, TextSorterDialog):
TextSorterDialog.setWindowTitle(_translate("TextSorterDialog", "Form", None))
self.remove_button.setText(_translate("TextSorterDialog", "Remove", None))
def retranslateUi(self, EditDialog):
EditDialog.setWindowTitle(_translate("EditDialog", "Form", None))
self.remove_button.setText(_translate("EditDialog", "Remove", None))
from PyKDE4.kdeui import KButtonGroup, KArrowButton, KPushButton, KRichTextWidget
from PyKDE4.kdeui import KButtonGroup, KArrowButton, KPushButton

BIN
texter/texter/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

View File

@ -0,0 +1,5 @@
P6
# CREATOR: GIMP PNM Filter Version 1.1
16 16
255
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>哪尿蝌<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>èň揪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E7A78D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><14><><EFBFBD>晻暢吵yyy挝<79><E68C9D><EFBFBD><EFBFBD>eee悙愔种<E68494><E7A78D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>tttQQQ<51><51><EFBFBD>种謑llbbb篌蟥è厖區^^ⅱ<><E285B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ppp鞍<70>666鬃讞棗<E8AE9E>畘~~破歧珑览纀bb┅<62><E29485><EFBFBD><EFBFBD>行协<E8A18C><E58D8F><EFBFBD><EFBFBD>圹勖妹666噜鄅hh适蕯敂牋<E69582><E7898B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>佑羽痧<E7BEBD><E797A7><EFBFBD>滗湫行<E6B9AB><E8A18C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E68FAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>悙悽ⅱ<E682BD><E285B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

9
texter/texter/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="icon" type="image/png" href="/icon.png" />
</head>
<body>
<img src="/texter_%d.mjpeg" alt="Smiley face" />
</body>
</html>

View File

@ -1,38 +1,54 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of texter package
#
# texter is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# texter is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with texter. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import
import cPickle
import os.path
import re
import subprocess
import sys
from math import pow
from operator import itemgetter
import traceback
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from PyQt4.QtGui import QPixmap
from PyKDE4.kdecore import ki18n, KCmdLineArgs, KAboutData
from PyKDE4.kdeui import KDialog, KActionCollection, KRichTextWidget, KComboBox, KPushButton, KRichTextWidget, KMainWindow, KToolBar, KApplication, KAction, KToolBarSpacerAction, KSelectAction, KToggleAction, KShortcut
from PyKDE4.kdeui import (KDialog, KActionCollection, KRichTextWidget,
KRichTextWidget, KMainWindow, KToolBar, KAction, KToolBarSpacerAction,
KSelectAction, KToggleAction, KShortcut)
from texter_ui import Ui_MainWindow, _fromUtf8
from text_sorter_ui import Ui_TextSorterDialog
from text_model import TextModel
from PyQt4.QtNetwork import QTcpServer, QTcpSocket
appName = "texter"
catalog = "448texter"
programName = ki18n("4.48 Psychose Texter")
version = "0.1"
from chaosc.argparser_groups import ArgParser
from chaosc.lib import resolve_host, logger
aboutData = KAboutData(appName, catalog, programName, version)
from psylib.mjpeg_streaming_server import *
from psylib.psyqt_base import PsyQtClientBase
KCmdLineArgs.init (sys.argv, aboutData)
from texter.texter_ui import Ui_MainWindow, _fromUtf8
from texter.edit_dialog_ui import Ui_EditDialog
from texter.text_model import TextModel
app = KApplication()
for path in QtGui.QIcon.themeSearchPaths():
print "%s/%s" % (path, QtGui.QIcon.themeName())
qtapp = QtGui.QApplication([])
# NOTE: if the QIcon.fromTheme method does not find any icons, you can use
@ -40,15 +56,20 @@ for path in QtGui.QIcon.themeSearchPaths():
# in your local icon directory:
# ln -s /your/icon/theme/directory $HOME/.icons/hicolor
class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
def __init__(self, parent = None):
super(TextSorterDialog, self).__init__(parent)
def get_preview_text(text):
return re.sub(" +", " ", text.replace("\n", " ")).strip()[:20]
class EditDialog(QtGui.QWidget, Ui_EditDialog):
def __init__(self, parent=None):
super(EditDialog, self).__init__(parent)
self.setupUi(self)
self.model = None
self.fill_list()
self.text_list.clicked.connect(self.slot_show_text)
self.remove_button.clicked.connect(self.slot_removeItem)
self.remove_button.clicked.connect(self.slot_remove_item)
self.move_up_button.clicked.connect(self.slot_text_up)
self.move_down_button.clicked.connect(self.slot_text_down)
self.text_list.clicked.connect(self.slot_toggle_buttons)
@ -71,9 +92,9 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
def fill_list(self):
self.model = self.parent().parent().model
self.text_list.setModel(self.model)
ix = self.parent().parent().current_index
index = self.model.index(ix, 0)
self.text_list.setCurrentIndex(index)
index = self.parent().parent().current_index
model_index = self.model.index(index, 0)
self.text_list.setCurrentIndex(model_index)
def slot_text_up(self):
@ -103,12 +124,11 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
def slot_show_text(self, model_index):
try:
self.text_preview.setTextOrHtml(self.parent().parent().model.text_db[model_index.row()][1])
self.text_preview.setHtml(self.parent().parent().model.text_db[model_index.row()][1])
except IndexError:
pass
def slot_removeItem(self):
def slot_remove_item(self):
index = self.text_list.currentIndex().row()
self.model.removeRows(index, 1)
index = self.model.index(0, 0)
@ -116,63 +136,6 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
self.text_list.clicked.emit(index)
self.parent().parent().db_dirty = True
class FadeAnimation(QtCore.QObject):
animation_started = QtCore.pyqtSignal()
animation_finished = QtCore.pyqtSignal()
animation_stopped = QtCore.pyqtSignal()
def __init__(self, live_text, fade_steps=6, parent=None):
super(FadeAnimation, self).__init__(parent)
self.live_text = live_text
self.fade_steps = fade_steps
self.current_alpha = 255
self.timer = None
def start_animation(self):
print "start_animation"
self.animation_started.emit()
if self.current_alpha == 255:
self.fade_delta = 255 / self.fade_steps
else:
self.fade_delta = -255 / self.fade_steps
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.slot_animate)
self.timer.start(100)
def slot_animate(self):
print "slot_animate"
print "current_alpha", self.current_alpha
if self.fade_delta > 0:
if self.current_alpha > 0:
self.live_text.setStyleSheet("color:%d, %d, %d;" % (self.current_alpha, self.current_alpha,self.current_alpha))
self.current_alpha -= self.fade_delta
else:
self.live_text.setStyleSheet("color:black;")
self.current_alpha = 0
self.timer.stop()
self.timer.timeout.disconnect(self.slot_animate)
self.timer.deleteLater()
self.timer = None
self.animation_finished.emit()
print "animation_finished"
else:
if self.current_alpha < 255:
self.live_text.setStyleSheet("color:%d,%d, %d;" % (self.current_alpha, self.current_alpha,self.current_alpha))
self.current_alpha -= self.fade_delta
else:
self.live_text.setStyleSheet("color:white")
self.current_alpha = 255
self.timer.stop()
self.timer.timeout.disconnect(self.slot_animate)
self.timer.deleteLater()
self.timer = None
self.animation_finished.emit()
print "animation_finished"
class TextAnimation(QtCore.QObject):
animation_started = QtCore.pyqtSignal()
animation_finished = QtCore.pyqtSignal()
@ -214,7 +177,6 @@ class TextAnimation(QtCore.QObject):
def slot_animate(self):
self.animation_started.emit()
parent = self.parent()
if self.it is None:
src_root_frame = self.src_document.rootFrame()
@ -271,13 +233,14 @@ class TextAnimation(QtCore.QObject):
self.count += 1
class MainWindow(KMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
class MainWindow(KMainWindow, Ui_MainWindow, MjpegStreamingConsumerInterface):
def __init__(self, args, parent=None):
self.args = args
#super(MainWindow, self).__init__()
#PsyQtClientBase.__init__(self)
KMainWindow.__init__(self, parent)
self.is_streaming = False
self.ffserver = None
self.ffmpeg = None
self.live_center_action = None
self.preview_center_action = None
self.live_size_action = None
@ -301,78 +264,81 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.is_auto_publish = False
self.setupUi(self)
self.win_id = self.live_text.winId()
self.fade_animation = FadeAnimation(self.live_text, 6, self)
self.fps = 12.5
self.http_server = MjpegStreamingServer((args.http_host, args.http_port), self, self.fps)
self.live_text.setLineWrapMode(QtGui.QTextEdit.LineWrapMode(QtGui.QTextEdit.FixedPixelWidth))
self.live_text.setLineWrapColumnOrWidth(768)
self.font = QtGui.QFont("monospace", self.default_size)
self.font.setStyleHint(QtGui.QFont.TypeWriter)
self.previous_action = None
self.next_action = None
self.publish_action = None
self.auto_publish_action = None
self.save_live_action = None
self.save_preview_action = None
self.save_action = None
self.dialog_widget = None
self.action_collection = None
self.streaming_action = None
self.text_combo = None
self.clear_live_action = None
self.clear_preview_action = None
self.toolbar = None
self.typer_animation_action = None
self.text_editor_action = None
self.create_toolbar()
#self.preview_text.document().setDefaultFont(self.font)
self.preview_text.setFont(self.font)
self.preview_text.setRichTextSupport(KRichTextWidget.RichTextSupport(0xffffffff))
self.preview_editor_collection = KActionCollection(self)
self.preview_text.createActions(self.preview_editor_collection)
self.live_text.setRichTextSupport(KRichTextWidget.RichTextSupport(0xffffffff))
#self.live_text.document().setDefaultFont(self.font)
self.live_text.setFont(self.font)
self.live_editor_collection = KActionCollection(self)
self.live_text.createActions(self.live_editor_collection)
self.filter_editor_actions()
self.create_toolbar()
self.slot_load()
qtapp.focusChanged.connect(self.focusChanged)
self.start_streaming()
self.show()
timer = QtCore.QTimer()
timer.start(2000)
timer.timeout.connect(lambda: None)
self.save_action.triggered.connect(self.slot_save)
def pubdir(self):
return os.path.dirname(os.path.abspath(__file__))
self.publish_action.triggered.connect(self.slot_publish)
self.clear_live_action.triggered.connect(self.slot_clear_live)
self.clear_preview_action.triggered.connect(self.slot_clear_preview)
self.text_combo.triggered[int].connect(self.slot_load_preview_text)
app.focusChanged.connect(self.focusChanged)
self.text_editor_action.triggered.connect(self.slot_open_dialog)
self.save_live_action.triggered.connect(self.slot_save_live_text)
self.save_preview_action.triggered.connect(self.slot_save_preview_text)
self.streaming_action.triggered.connect(self.slot_toggle_streaming)
self.auto_publish_action.toggled.connect(self.slot_auto_publish)
self.typer_animation_action.toggled.connect(self.slot_toggle_animation)
self.preview_size_action.triggered[QtGui.QAction].connect(self.slot_preview_font_size)
self.live_size_action.triggered[QtGui.QAction].connect(self.slot_live_font_size)
#self.fade_action.triggered.connect(self.slot_fade)
self.next_action.triggered.connect(self.slot_next_item)
self.previous_action.triggered.connect(self.slot_previous_item)
self.getLiveCoords()
print "desktop", app.desktop().availableGeometry()
def getLiveCoords(self):
public_rect = self.live_text.geometry()
global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
x = global_rect.x()
y = global_rect.y()
self.statusBar().showMessage("live text editor dimensions: x=%r, y=%r, width=%r, height=%r" % (x, y, global_rect.width(), global_rect.height()))
def getPreviewCoords(self):
public_rect = self.preview_text.geometry()
global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
return global_rect.x(), global_rect.y()
def render_image(self):
public_rect = self.live_text_rect()
#global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
pixmap = QPixmap.grabWindow(self.win_id, public_rect.x() + 1, public_rect.y() + 1, 768, 576)
buf = QBuffer()
buf.open(QIODevice.WriteOnly)
pixmap.save(buf, "JPG", 75)
return buf.data()
def filter_editor_actions(self):
disabled_action_names = [
"action_to_plain_text",
"format_painter",
"direction_ltr",
"direction_rtl",
"format_font_family",
#"format_font_size",
"format_text_background_color",
"format_list_style",
"format_list_indent_more",
@ -382,7 +348,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
"format_text_strikeout",
"format_text_italic",
"format_align_right",
#"format_align_justify",
"manage_link",
"format_text_subscript",
"format_text_superscript",
@ -391,7 +356,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
for action in self.live_editor_collection.actions():
text = str(action.objectName())
print "text", text
if text in disabled_action_names:
action.setVisible(False)
@ -417,10 +381,10 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.slot_set_preview_defaults()
self.slot_set_live_defaults()
def create_toolbar(self):
self.toolbar = KToolBar(self, True, True)
self.toolbar.setIconDimensions(16)
self.toolbar.setAllowedAreas(QtCore.Qt.BottomToolBarArea)
self.toolbar.setMovable(False)
self.toolbar.setFloatable(False)
@ -432,32 +396,31 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.action_collection.addAssociatedWidget(self.toolbar)
self.clear_live_action = self.action_collection.addAction("clear_live_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("edit-clear"))
icon = QtGui.QIcon(":texter/images/edit-clear.png")
self.clear_live_action.setIcon(icon)
self.clear_live_action.setIconText("clear live")
self.clear_live_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Q)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.save_live_action = self.action_collection.addAction("save_live_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-new"))
icon = QtGui.QIcon(":texter/images/document-new.png")
self.save_live_action.setIcon(icon)
self.save_live_action.setIconText("save live")
self.save_live_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_W)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.clear_preview_action = self.action_collection.addAction("clear_preview_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("edit-clear"))
icon = QtGui.QIcon(":texter/images/edit-clear.png")
self.clear_preview_action.setIcon(icon)
self.clear_preview_action.setIconText("clear preview")
#self.clear_preview_action.setObjectName("clear_preview")
self.clear_preview_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_A)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.save_preview_action = self.action_collection.addAction("save_preview_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-new"))
icon = QtGui.QIcon(":texter/images/document-new.png")
self.save_preview_action.setIcon(icon)
self.save_preview_action.setIconText("save preview")
self.save_preview_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.publish_action = self.action_collection.addAction("publish_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("edit-copy"))
icon = QtGui.QIcon(":texter/images/edit-copy.png")
self.publish_action.setIcon(icon)
self.publish_action.setIconText("publish")
self.publish_action.setShortcutConfigurable(True)
@ -467,14 +430,14 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.auto_publish_action = KToggleAction(self.action_collection)
self.action_collection.addAction("auto publish", self.auto_publish_action)
icon = QtGui.QIcon.fromTheme(_fromUtf8("view-refresh"))
icon = QtGui.QIcon(":texter/images/view-refresh.png")
self.auto_publish_action.setIcon(icon)
self.auto_publish_action.setObjectName("auto_publish_action")
self.auto_publish_action.setIconText("auto publish")
self.auto_publish_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_P)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.typer_animation_action = KToggleAction(self.action_collection)
icon = QtGui.QIcon.fromTheme(_fromUtf8("media-playback-stop"))
icon = QtGui.QIcon(":texter/images/media-playback-stop.png")
self.typer_animation_action.setIcon(icon)
self.typer_animation_action.setIconText("animate")
self.typer_animation_action.setObjectName("typer_animation_action")
@ -482,7 +445,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.action_collection.addAction("typer_animation_action", self.typer_animation_action)
self.text_editor_action = self.action_collection.addAction("text_editor_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-open-data"))
icon = QtGui.QIcon(":texter/images/document-open-data.png")
self.text_editor_action.setIcon(icon)
self.text_editor_action.setIconText("edit")
self.text_editor_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_O)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
@ -490,13 +453,13 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.toolbar.insertSeparator(self.text_editor_action)
self.save_action = self.action_collection.addAction("save_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-save"))
icon = QtGui.QIcon(":texter/images/document-save.png")
self.save_action.setIcon(icon)
self.save_action.setIconText("save")
self.save_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_S)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.streaming_action = KToggleAction(self.action_collection)
icon = QtGui.QIcon.fromTheme(_fromUtf8("media-record"))
icon = QtGui.QIcon(":texter/images/media-record.png")
self.streaming_action.setIcon(icon)
self.streaming_action.setIconText("stream")
self.streaming_action.setObjectName("stream")
@ -506,37 +469,49 @@ class MainWindow(KMainWindow, Ui_MainWindow):
spacer = KToolBarSpacerAction(self.action_collection)
self.action_collection.addAction("1_spacer", spacer)
#self.fade_action = self.action_collection.addAction("fade_action")
##icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page"))
##self.fade_action.setIcon(icon)
#self.fade_action.setIconText("fade")
#self.fade_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_F)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.previous_action = self.action_collection.addAction("previous_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page"))
icon = QtGui.QIcon(":texter/images/go-previous-view-page.png")
self.previous_action.setIcon(icon)
self.previous_action.setIconText("previous")
self.previous_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Left)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.text_combo = KSelectAction(self.action_collection)
self.text_combo.setEditable(False)
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-open-recent"))
icon = QtGui.QIcon(":texter/images/document-open-recent.png")
self.text_combo.setIcon(icon)
self.text_combo.setIconText("saved texts")
self.text_combo.setObjectName("text_combo")
self.action_collection.addAction("saved texts", self.text_combo)
self.next_action = self.action_collection.addAction("next_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("go-next-view-page"))
icon = QtGui.QIcon(":texter/images/go-next-view-page.png")
self.next_action.setIcon(icon)
self.next_action.setIconText("next")
self.next_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_Right)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.toolbar.addSeparator()
self.save_action.triggered.connect(self.slot_save)
self.publish_action.triggered.connect(self.slot_publish)
self.clear_live_action.triggered.connect(self.slot_clear_live)
self.clear_preview_action.triggered.connect(self.slot_clear_preview)
self.text_combo.triggered[int].connect(self.slot_load_preview_text)
self.text_editor_action.triggered.connect(self.slot_open_dialog)
self.save_live_action.triggered.connect(self.slot_save_live_text)
self.save_preview_action.triggered.connect(self.slot_save_preview_text)
self.streaming_action.triggered.connect(self.slot_toggle_streaming)
self.auto_publish_action.toggled.connect(self.slot_auto_publish)
self.typer_animation_action.toggled.connect(self.slot_toggle_animation)
self.preview_size_action.triggered[QtGui.QAction].connect(self.slot_preview_font_size)
self.live_size_action.triggered[QtGui.QAction].connect(self.slot_live_font_size)
self.next_action.triggered.connect(self.slot_next_item)
self.previous_action.triggered.connect(self.slot_previous_item)
self.streaming_action.setChecked(True)
def closeEvent(self, event):
self.stop_streaming()
logger.info("closeEvent")
if self.db_dirty:
self.dialog = KDialog(self)
self.dialog.setCaption("4.48 texter - text db not saved")
@ -545,23 +520,37 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.dialog.setButtons(KDialog.ButtonCodes(KDialog.Ok | KDialog.Cancel))
self.dialog.okClicked.connect(self.slot_save)
self.dialog.exec_()
event.accept()
def live_text_rect(self):
return self.live_text.geometry()
def stop_streaming(self):
self.is_streaming = False
if self.ffmpeg is not None:
self.ffmpeg.kill()
self.ffmpeg = None
if self.ffserver is not None:
self.ffserver.kill()
self.ffserver = None
self.http_server.stop()
def start_streaming(self):
public_rect = self.live_text.geometry()
global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
self.ffserver = subprocess.Popen("ffserver -f /etc/ffserver.conf", shell=True, close_fds=True)
self.ffmpeg = subprocess.Popen("ffmpeg -f x11grab -show_region 1 -s 768x576 -r 30 -i :0.0+%d,%d -vcodec mjpeg -pix_fmt yuvj444p -r 30 -aspect 4:3 http://localhost:8090/webcam.ffm" % (global_rect.x()+3, global_rect.y()+3), shell=True, close_fds=True)
self.http_server.listen(port=self.args.http_port)
self.is_streaming = True
def fill_combo_box(self):
if self.dialog is not None:
self.dialog.deleteLater()
self.dialog = None
self.text_combo.clear()
current_row = -1
for index, list_obj in enumerate(self.model.text_db):
preview, text = list_obj
self.text_combo.addAction(preview)
if list_obj == self.current_object:
current_row = index
if current_row == -1:
current_row = self.current_index
self.slot_load_preview_text(current_row)
self.text_combo.setCurrentItem(current_row)
def focusChanged(self, old, new):
if new == self.preview_text:
self.live_editor_collection.clearAssociatedWidgets()
@ -570,18 +559,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.preview_editor_collection.clearAssociatedWidgets()
self.live_editor_collection.addAssociatedWidget(self.toolbar)
def custom_clear(self, cursor):
cursor.beginEditBlock()
cursor.movePosition(QtGui.QTextCursor.Start);
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.KeepAnchor);
cursor.removeSelectedText()
cursor.endEditBlock()
def get_preview_text(self, text):
return re.sub(" +", " ", text.replace("\n", " ")).strip()[:20]
def slot_auto_publish(self, state):
self.is_auto_publish = bool(state)
@ -589,11 +566,10 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.is_animate = bool(state)
def slot_toggle_streaming(self):
if self.ffserver is None:
self.start_streaming()
else:
if self.is_streaming:
self.stop_streaming()
else:
self.start_streaming()
def slot_next_item(self):
try:
@ -603,7 +579,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
except ZeroDivisionError:
pass
def slot_previous_item(self):
try:
self.current = (self.text_combo.currentItem() - 1) % len(self.model.text_db)
@ -612,26 +587,22 @@ class MainWindow(KMainWindow, Ui_MainWindow):
except ZeroDivisionError:
pass
def slot_publish(self):
if self.is_animate:
self.animation.start_animation(self.preview_text, self.live_text, 0)
else:
self.live_text.setTextOrHtml(self.preview_text.textOrHtml())
def slot_live_font_size(self, action):
self.default_size = self.live_size_action.fontSize()
self.slot_set_preview_defaults()
self.slot_set_live_defaults()
def slot_preview_font_size(self, action):
self.default_size = self.preview_size_action.fontSize()
self.slot_set_live_defaults()
self.slot_set_preview_defaults()
def slot_toggle_publish(self, state=None):
if state:
@ -639,7 +610,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
else:
self.slot_clear_live()
def slot_set_preview_defaults(self):
self.preview_center_action.setChecked(True)
self.preview_text.alignCenter()
@ -668,23 +638,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
if self.fade_animation.timer is None:
self.fade_animation.start_animation()
def fill_combo_box(self):
if self.dialog is not None:
self.dialog.deleteLater()
self.dialog = None
self.text_combo.clear()
current_row = -1
for ix, list_obj in enumerate(self.model.text_db):
preview, text = list_obj
self.text_combo.addAction(preview)
if list_obj == self.current_object:
current_row = ix
if current_row == -1:
current_row = self.current_index
self.slot_load_preview_text(current_row)
self.text_combo.setCurrentItem(current_row)
def slot_load_preview_text(self, index):
try:
@ -697,7 +650,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
def slot_save_live_text(self):
text = self.live_text.toHtml()
preview = self.get_preview_text(unicode(self.live_text.toPlainText()))
preview = get_preview_text(unicode(self.live_text.toPlainText()))
if not preview:
return
old_item = self.model.text_by_preview(preview)
@ -720,7 +673,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
def slot_save_preview_text(self):
text = self.preview_text.toHtml()
preview = self.get_preview_text(unicode(self.preview_text.toPlainText()))
preview = get_preview_text(unicode(self.preview_text.toPlainText()))
if not preview:
return
@ -747,7 +700,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
cPickle.dump(self.model.text_db, f, cPickle.HIGHEST_PROTOCOL)
self.db_dirty = False
def slot_open_dialog(self):
self.current_index = self.text_combo.currentItem()
self.current_object = self.model.text_db[self.current_index]
@ -756,42 +708,61 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.dialog = None
self.dialog = KDialog(self)
self.dialog_widget = TextSorterDialog(self.dialog)
self.dialog.setButtons(KDialog.Close)
self.dialog_widget = EditDialog(self.dialog)
self.dialog.setMainWidget(self.dialog_widget)
pos_x, pos_y = self.getPreviewCoords()
self.dialog.move(pos_x, 0)
rect = app.desktop().availableGeometry()
global_width = rect.width()
global_height = rect.height()
x = global_width - pos_x - 10
#self.dialog.setFixedSize(x, global_height-40)
self.dialog.okClicked.connect(self.fill_combo_box)
self.dialog.move(pos_x, self.pos().y())
self.dialog.exec_()
self.fill_combo_box()
def slot_load(self):
path = os.path.expanduser("~/.texter")
if not os.path.isdir(path):
os.mkdir(path)
try:
f = open(os.path.join(path, "texter.db"))
db_file = open(os.path.join(path, "texter.db"))
except IOError:
return
try:
self.model.text_db = [list(i) for i in cPickle.load(f)]
except Exception, e:
print e
self.model.text_db = [list(i) for i in cPickle.load(db_file)]
except ValueError, error:
logger.exception(error)
self.fill_combo_box()
self.text_combo.setCurrentItem(0)
self.slot_load_preview_text(0)
def sigint_handler(self, ex_cls, ex, tb):
"""Handler for the SIGINT signal."""
if ex_cls == KeyboardInterrupt:
logger.info("found KeyboardInterrupt")
QtGui.QApplication.exit()
else:
logger.critical(''.join(traceback.format_tb(tb)))
logger.critical('{0}: {1}'.format(ex_cls, ex))
def main():
window = MainWindow()
app.exec_()
arg_parser = ArgParser("texter")
arg_parser.add_global_group()
client_group = arg_parser.add_client_group()
arg_parser.add_argument(client_group, '-x', "--http_host", default="::",
help='my host, defaults to "::"')
arg_parser.add_argument(client_group, '-X', "--http_port", default=9001,
type=int, help='my port, defaults to 9001')
arg_parser.add_chaosc_group()
arg_parser.add_subscriber_group()
args = arg_parser.finalize()
args.http_host, args.http_port = resolve_host(args.http_host, args.http_port, args.address_family)
args.chaosc_host, args.chaosc_port = resolve_host(args.chaosc_host, args.chaosc_port, args.address_family)
window = MainWindow(args, None)
sys.excepthook = window.sigint_handler
qtapp.exec_()
if ( __name__ == '__main__' ):
if __name__ == '__main__':
main()

View File

@ -16,11 +16,9 @@ class TextModel(QtCore.QAbstractTableModel):
return len(self.text_db)
def columnCount(self, parent=QtCore.QModelIndex()):
return 2
return 1
def data(self, index, role):
if role not in (1,3,4,5,6,7,8,9,10,13):
print "role", role
if not index.isValid() or \
not 0 <= index.row() < self.rowCount():
return QVariant()
@ -28,12 +26,9 @@ class TextModel(QtCore.QAbstractTableModel):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
return self.text_db[row][column]
print "data", row, column, row
return QtCore.QVariant(self.text_db[row][column])
#return "foo bar"
elif role == QtCore.Qt.ForegroundRole:
return QtGui.QBrush(QtCore.Qt.black)
elif role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(QtCore.Qt.white)
return QtCore.QVariant()
@ -47,6 +42,12 @@ class TextModel(QtCore.QAbstractTableModel):
return QtCore.QVariant()
def setData(self, index, value, role):
if (not index.isValid() or
not 0 <= index.row() < self.rowCount()):
print "setData index not valid"
return False
print "setData", index.row(), index.column(), value, role
if role == QtCore.Qt.EditRole:
text = value.toString()
@ -54,14 +55,16 @@ class TextModel(QtCore.QAbstractTableModel):
return False
else:
self.text_db[index.row()][index.column()] = text
return True
else:
return False
def flags(self, index):
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
if index.column() == 0:
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
else:
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
def supportedDropActions(self):
return QtCore.Qt.MoveAction
def insertRows(self, row, count, parent=QtCore.QModelIndex()):
self.beginInsertRows(parent, row, row+count+1)

View File

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>text_sorter_dialog</class>
<widget class="QDialog" name="text_sorter_dialog">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListView" name="text_list">
<property name="minimumSize">
<size>
<width>0</width>
<height>576</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>576</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="KButtonGroup" name="kbuttongroup">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="KPushButton" name="remove_button">
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset theme="edit-delete"/>
</property>
</widget>
</item>
<item>
<widget class="KArrowButton" name="move_up_button"/>
</item>
<item>
<widget class="KArrowButton" name="move_down_button">
<property name="arrowType" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="KRichTextWidget" name="text_preview"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KArrowButton</class>
<extends>QPushButton</extends>
<header>karrowbutton.h</header>
</customwidget>
<customwidget>
<class>KRichTextEdit</class>
<extends>KTextEdit</extends>
<header>krichtextedit.h</header>
</customwidget>
<customwidget>
<class>KButtonGroup</class>
<extends>QGroupBox</extends>
<header>kbuttongroup.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KPushButton</class>
<extends>QPushButton</extends>
<header>kpushbutton.h</header>
</customwidget>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
<customwidget>
<class>KRichTextWidget</class>
<extends>KRichTextEdit</extends>
<header>krichtextwidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>text_sorter_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>text_sorter_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

1
texter/texter/texter.html Symbolic link
View File

@ -0,0 +1 @@
index.html

View File

@ -1,5 +1,16 @@
<RCC>
<qresource prefix="texter">
<file>images/document-new.png</file>
<file>images/document-open-data.png</file>
<file>images/document-open-recent.png</file>
<file>images/document-save.png</file>
<file>images/edit-clear.png</file>
<file>images/edit-copy.png</file>
<file>images/go-next-view-page.png</file>
<file>images/go-previous-view-page.png</file>
<file>images/media-playback-stop.png</file>
<file>images/media-record.png</file>
<file>images/view-refresh.png</file>
<file>icon.png</file>
</qresource>
</RCC>

File diff suppressed because it is too large Load Diff

View File

@ -1,395 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1554</width>
<height>617</height>
</rect>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>169</red>
<green>167</green>
<blue>167</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>244</red>
<green>244</green>
<blue>244</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="windowTitle">
<string>4.48 Texter</string>
</property>
<property name="windowIcon">
<iconset resource="texter.qrc">
<normaloff>:/texter/icon.png</normaloff>:/texter/icon.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="KRichTextWidget" name="live_text">
<property name="minimumSize">
<size>
<width>768</width>
<height>576</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>768</width>
<height>576</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>22</pointsize>
</font>
</property>
<property name="cursor" stdset="0">
<cursorShape>BlankCursor</cursorShape>
</property>
<property name="toolTip">
<string/>
</property>
<property name="statusTip">
<string/>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="acceptRichText">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="KPushButton" name="clear_live_button">
<property name="toolTip">
<string>clear live text [F1]</string>
</property>
<property name="icon">
<iconset theme="edit-clear">
<normaloff/>
</iconset>
</property>
<property name="shortcut">
<string>F1</string>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="live_save_button">
<property name="toolTip">
<string>save live text [F2]</string>
</property>
<property name="icon">
<iconset theme="document-save">
<normaloff/>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="KPushButton" name="streaming_button">
<property name="toolTip">
<string>starts/stops live textfield streaming [F9]</string>
</property>
<property name="icon">
<iconset theme="media-record"/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="KRichTextWidget" name="preview_text">
<property name="minimumSize">
<size>
<width>400</width>
<height>576</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>768</width>
<height>576</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>22</pointsize>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="toolTip">
<string>preview text</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="acceptRichText">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KPushButton" name="clear_preview_button">
<property name="toolTip">
<string>clear preview text [F4]</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="icon">
<iconset theme="edit-clear">
<normaloff/>
</iconset>
</property>
<property name="shortcut">
<string>F2</string>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="preview_save_button">
<property name="icon">
<iconset theme="document-save">
<normaloff/>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="publish_button">
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="toolTip">
<string>go live with text [F5]</string>
</property>
<property name="icon">
<iconset theme="media-playback-start">
<normaloff/>
</iconset>
</property>
<property name="shortcut">
<string>F4</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="previous_button">
<property name="toolTip">
<string>load previous text [F6]</string>
</property>
<property name="icon">
<iconset theme="media-skip-backward">
<normaloff/>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="next_button">
<property name="toolTip">
<string>load next text [F7]</string>
</property>
<property name="icon">
<iconset theme="media-skip-forward">
<normaloff/>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="KComboBox" name="text_combo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="KPushButton" name="text_open_button">
<property name="toolTip">
<string>edit sorting of saved texts [F10]</string>
</property>
<property name="icon">
<iconset theme="document-open">
<normaloff/>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>KRichTextEdit</class>
<extends>KTextEdit</extends>
<header>krichtextedit.h</header>
</customwidget>
<customwidget>
<class>KComboBox</class>
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
<customwidget>
<class>KPushButton</class>
<extends>QPushButton</extends>
<header>kpushbutton.h</header>
</customwidget>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
<customwidget>
<class>KRichTextWidget</class>
<extends>KRichTextEdit</extends>
<header>krichtextwidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>live_text</tabstop>
<tabstop>preview_text</tabstop>
<tabstop>clear_preview_button</tabstop>
<tabstop>clear_live_button</tabstop>
</tabstops>
<resources>
<include location="texter.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,403 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1475</width>
<height>651</height>
</rect>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>169</red>
<green>167</green>
<blue>167</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>244</red>
<green>244</green>
<blue>244</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="windowTitle">
<string>4.48 Texter</string>
</property>
<property name="windowIcon">
<iconset resource="texter.qrc">
<normaloff>:/texter/icon.png</normaloff>:/texter/icon.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KRichTextWidget" name="live_text">
<property name="minimumSize">
<size>
<width>775</width>
<height>582</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>775</width>
<height>582</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Highlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Link">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Highlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Link">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Highlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Link">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="acceptRichText">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
<property name="richTextSupport">
<set>KRichTextWidget::SupportAlignment|KRichTextWidget::SupportFontFamily|KRichTextWidget::SupportFontSize|KRichTextWidget::SupportTextForegroundColor</set>
</property>
</widget>
</item>
<item>
<widget class="KRichTextWidget" name="preview_text">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>10</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>582</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>775</width>
<height>582</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="toolTip">
<string>preview text</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="acceptRichText">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
<property name="richTextSupport">
<set>KRichTextWidget::SupportAlignment|KRichTextWidget::SupportChangeListStyle|KRichTextWidget::SupportFontFamily|KRichTextWidget::SupportFontSize|KRichTextWidget::SupportTextForegroundColor</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>KRichTextEdit</class>
<extends>KTextEdit</extends>
<header>krichtextedit.h</header>
</customwidget>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
<customwidget>
<class>KRichTextWidget</class>
<extends>KRichTextEdit</extends>
<header>krichtextwidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>live_text</tabstop>
<tabstop>preview_text</tabstop>
</tabstops>
<resources>
<include location="texter.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,559 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TextSorterDialog</class>
<widget class="QWidget" name="TextSorterDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1084</width>
<height>633</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QListView" name="text_list">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>576</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>576</height>
</size>
</property>
</widget>
<widget class="KRichTextWidget" name="text_preview">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>576</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>768</width>
<height>576</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Midlight">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Dark">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Mid">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="BrightText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Shadow">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="AlternateBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipBase">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
<colorrole role="ToolTipText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
<widget class="KButtonGroup" name="kbuttongroup">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KArrowButton" name="move_down_button">
<property name="arrowType" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item>
<widget class="KArrowButton" name="move_up_button"/>
</item>
<item>
<widget class="KPushButton" name="remove_button">
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset theme="edit-delete">
<normaloff>../../../../</normaloff>../../../../</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KArrowButton</class>
<extends>QPushButton</extends>
<header>karrowbutton.h</header>
</customwidget>
<customwidget>
<class>KRichTextEdit</class>
<extends>KTextEdit</extends>
<header>krichtextedit.h</header>
</customwidget>
<customwidget>
<class>KButtonGroup</class>
<extends>QGroupBox</extends>
<header>kbuttongroup.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KPushButton</class>
<extends>QPushButton</extends>
<header>kpushbutton.h</header>
</customwidget>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
<customwidget>
<class>KRichTextWidget</class>
<extends>KRichTextEdit</extends>
<header>krichtextwidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -2,7 +2,7 @@
# Resource object code
#
# Created: Sa. Apr 12 08:49:54 2014
# Created: So. Mai 11 12:37:13 2014
# by: The Resource Compiler for PyQt (Qt v4.8.5)
#
# WARNING! All changes made in this file will be lost!
@ -47,6 +47,482 @@ qt_resource_data = "\
\x38\x8f\xeb\x38\x43\x35\x89\xdd\x94\xa5\xf7\x2f\xa8\x01\x6a\x80\
\x1a\xa0\x06\xf8\xdf\xf2\x1b\xf1\xb2\x57\x16\x4f\x60\xf0\x28\x00\
\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x7f\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\x1e\x75\
\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x07\x03\x0a\x15\
\x1c\xbc\x0f\x78\x91\x00\x00\x01\x11\x50\x4c\x54\x45\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x32\x71\x2d\x8f\x90\x91\
\x93\x93\x94\x8c\x8e\x8f\x90\x90\x91\x18\x48\x1d\x18\x49\x28\x1b\
\x57\x19\x1d\x56\x17\x21\x62\x1e\x27\x70\x28\x32\x82\x34\x3d\x8e\
\x3c\x3e\x7e\x18\x54\x9d\x4c\x55\x87\x5d\x55\x9e\x4f\x5b\x9d\x56\
\x63\x9f\x38\x64\xa7\x53\x74\xa4\x77\x75\xac\x0c\x77\xb2\x50\x7c\
\xb3\x78\x85\xbe\x20\x8b\xa9\x92\x8e\xc4\x23\x8f\x94\x92\x91\xc8\
\x24\x99\xd2\x0b\x9b\x9d\x9e\x9e\x9f\xa0\x9f\x9f\xa0\x9f\xad\xa3\
\xa0\xd7\x0c\xa2\xa3\xa3\xa6\xa7\xa8\xa7\xa7\xa8\xa8\xa8\xa8\xa8\
\xd0\x6a\xaa\xd0\x72\xb9\xb9\xb9\xba\xba\xba\xbf\xde\x9a\xc5\xc5\
\xc5\xc5\xc6\xc6\xc8\xca\xcb\xd2\xd2\xd2\xd2\xda\xd4\xd2\xe2\xd2\
\xd8\xe9\xd6\xd9\xd9\xd9\xdb\xdb\xdb\xdf\xed\xde\xe3\xe3\xe3\xe9\
\xef\xe9\xea\xea\xea\xee\xee\xee\xee\xef\xef\xef\xef\xef\xf0\xf0\
\xf0\xf2\xf7\xf1\xf4\xf5\xf5\xf5\xf5\xf5\xf5\xf6\xf6\xf6\xf6\xf6\
\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf9\xf9\xf9\xf9\xf9\xfa\xfa\xfa\xfb\
\xfb\xfb\xfc\xfc\xfc\xfd\xfd\xfd\xfe\xfe\xfe\xff\xff\xff\x79\x1f\
\xc0\x25\x00\x00\x00\x14\x74\x52\x4e\x53\x00\x10\x13\x15\x1b\x1c\
\x24\x25\x26\x3a\x3b\x44\x4e\x4f\x7e\x8b\xdb\xdb\xdc\xdc\x37\x8a\
\x8c\x11\x00\x00\x00\x01\x62\x4b\x47\x44\x5a\x03\xbb\xa5\xa2\x00\
\x00\x00\xc7\x49\x44\x41\x54\x78\xda\x3d\x8c\x7b\x57\x01\x51\x14\
\x47\xaf\x47\x1e\xdd\x48\x49\x09\x21\xa2\xbc\x9a\xd0\x28\xc9\x23\
\x0a\x0d\xaa\x99\xdc\xb9\xe7\xce\xf7\xff\x20\x9d\xb3\xe6\xae\x7e\
\x7f\x9d\xbd\xd7\x5e\x87\x05\xe3\xff\x0b\x30\x5a\xc2\xd3\x7b\x7b\
\xe7\x5a\xec\x7e\x9c\xbd\x10\xa2\x74\x75\x7c\x48\x55\x42\xd9\xbf\
\x42\xb8\xae\x9b\x7f\xa9\xd4\xb7\x1e\x47\xb1\x47\x94\x52\xe6\x9e\
\x06\xb5\xf2\x0c\x85\x27\x10\x01\xe0\xf2\xb6\xd5\xb8\xae\x92\x20\
\x56\x0a\xb2\xed\x6e\xa1\xb8\xe4\xec\x08\x05\x28\x69\x5b\x17\x37\
\xe7\x77\x12\x48\x20\xc3\xca\x34\xce\x32\x0f\x00\x0a\x85\x42\x61\
\x9b\x0a\xa6\xcd\x85\xb5\xfe\xf6\x0b\xd8\x18\xe0\x74\x46\xa6\xd1\
\x1f\x6b\xf1\xf9\xe8\xdc\x4f\xb0\x72\xd2\x07\xfe\x8f\xaf\xd7\xde\
\x9c\xaa\xd3\x18\x63\x21\xce\x79\x72\xf8\xfc\x41\x55\x2a\xca\xfc\
\xe9\xea\x24\xa2\x99\x2a\x5a\x98\xee\x3f\xcd\x34\x32\x2a\x58\xbf\
\xee\x5f\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x6a\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\x1e\x75\
\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x07\x03\x0f\x2d\
\x32\x71\x8d\x0b\x4e\x00\x00\x01\x0b\x50\x4c\x54\x45\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x90\x91\x93\x93\x94\
\x8c\x8e\x8f\x90\x90\x91\x0b\x47\x16\x16\x47\x1d\x18\x5c\x1c\x20\
\x59\x1a\x23\x6e\x25\x28\x56\x32\x34\x83\x35\x3f\x8f\x3c\x40\x7e\
\x17\x54\x98\x51\x54\x9d\x4c\x55\x95\x2a\x5a\x8a\x61\x5d\xa2\x58\
\x61\xa5\x51\x73\xaf\x4e\x74\xa9\x70\x75\x91\x7c\x84\xb7\x0d\x84\
\xbd\x23\x87\xaf\x89\x89\xc2\x20\x90\xc7\x24\x9d\xd4\x0d\x9f\x9f\
\xa0\xa1\xd9\x0c\xa6\xa7\xa8\xa6\xc6\xa4\xa7\xa7\xa8\xa7\xd0\x6a\
\xa8\xa8\xa8\xab\xd1\x71\xaf\xaf\xaf\xb0\xb0\xb0\xbf\xde\x99\xc0\
\xc0\xc0\xc1\xc1\xc1\xc5\xc6\xc6\xc8\xca\xcb\xca\xd6\xcd\xcc\xe2\
\xca\xd3\xdc\xd6\xd6\xe4\xd7\xe2\xee\xe1\xe5\xe5\xe5\xea\xea\xea\
\xea\xef\xea\xed\xf2\xed\xee\xee\xee\xee\xef\xef\xee\xf2\xef\xef\
\xef\xef\xf0\xf0\xf0\xf4\xf5\xf5\xf5\xf5\xf5\xf5\xf6\xf5\xf5\xf6\
\xf6\xf6\xf6\xf6\xf6\xf7\xf6\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf9\xf8\
\xf9\xf9\xf9\xfa\xfa\xfa\xfb\xfb\xfb\xfc\xfc\xfc\xfd\xfd\xfd\xfd\
\xfe\xfd\xfe\xfe\xfe\xff\xff\xff\xd9\x1d\x54\xe2\x00\x00\x00\x13\
\x74\x52\x4e\x53\x00\x10\x13\x15\x1b\x1c\x24\x25\x26\x3a\x44\x4e\
\x4f\x6f\x7e\xdb\xdb\xdc\xdc\xc6\x90\x16\x3a\x00\x00\x00\x01\x62\
\x4b\x47\x44\x58\xed\xb5\xc4\x8e\x00\x00\x00\xb9\x49\x44\x41\x54\
\x18\x19\x05\xc1\x5d\x2e\x03\x51\x18\x00\xd0\xf3\xdd\x7e\x4a\x91\
\x8c\x90\x88\x48\x08\x89\x58\x8d\xd5\x76\x05\x7e\x36\x60\x05\xbc\
\xe0\x41\x24\xd5\xd0\x76\x66\x6a\xee\x38\x27\xcb\x2e\x80\x76\x44\
\xee\xdf\xc1\xc7\x70\xc1\x7c\x8d\xe4\x3b\x7f\x16\x8b\xc9\x56\x4c\
\x66\xb4\x69\x9c\xfe\xbe\xd5\xb3\xf7\xab\xe2\x1a\xf3\x64\xf1\x3a\
\x6d\x86\x71\x35\x0d\x90\xe2\xb3\x64\x37\xd6\x12\x81\x90\x9c\xbf\
\xac\x9a\x49\x15\x01\x72\x74\x7c\xf2\xfc\xd5\xd4\x21\x82\x52\x25\
\x11\xcd\xe9\x4b\x4c\xa3\xa8\xb5\x48\x23\x71\x79\xb0\xd9\x29\x43\
\xdf\x0e\x7b\x52\x40\x73\x54\xea\xd7\xb2\x2f\x87\x12\x8c\xe8\x96\
\xb7\xb5\x7f\xda\x26\x08\x6a\xd7\xd7\xfe\x71\xb3\xcd\x76\x4e\xde\
\x60\xc8\xfe\xbe\xed\xe4\xb0\xe6\x00\x65\x67\xf6\xb0\xe9\x49\x68\
\xe7\xa0\xff\xc3\x3f\x9e\x71\x4d\xf4\x47\x46\x2f\xfd\x00\x00\x00\
\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x43\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xc0\x49\x44\
\x41\x54\x78\xda\x8d\x8f\xbd\x6b\x53\x51\x18\x87\x9f\x73\x72\xc1\
\xb6\x41\x90\x82\x52\x2a\xc5\x39\xdd\x8c\x93\x75\xab\x83\x9b\xbb\
\x53\xbb\xe4\x3f\x68\x07\x11\x8a\x25\xd4\x82\x43\x87\xa2\x20\x0e\
\x15\x07\xe9\x6a\x16\xc5\x3d\xb5\x88\xa1\x1f\x42\xd3\x4d\x25\xe8\
\xcd\x87\x83\x12\x92\x9b\x8f\x9b\x9c\xd7\xe6\xe0\xe1\x70\x89\x5f\
\x3f\xf8\x71\xce\x19\x9e\xe7\x7d\x8f\x02\x2e\x00\xf3\xfc\x2b\xab\
\xdc\xce\x5c\xcb\x2c\x65\x2f\x67\xa7\x0f\xab\x87\xf5\x72\xbb\xfc\
\x40\x96\xe5\x49\x30\x82\x1b\x8d\xc6\x9e\x11\x41\x6b\x6d\xab\x94\
\x4a\xf4\xd9\xc7\x1d\x76\x7f\xec\xb2\x78\x69\x91\xcd\xf9\x4d\xee\
\x95\xef\xce\xa5\xbf\xa5\x1f\xab\x1d\x25\x1a\xc0\x08\x7f\xcd\xf6\
\xe9\x36\xd5\x4e\x95\xfd\x4f\x05\x00\x3e\x57\x0b\x98\x41\x4d\x63\
\x58\x0d\x00\x52\x29\xeb\xb1\xd3\xdc\x06\xda\x6f\x40\xed\x7b\x8d\
\xe8\x4e\x84\xcb\x8b\x9b\x65\x00\xd4\x23\x35\x1b\x00\x16\x42\x04\
\xf5\xeb\x0b\x16\x76\xe7\x59\x67\xae\xcc\x10\x3c\x57\x5c\x05\xde\
\x2f\x09\xb9\x82\xe2\x40\x80\x8b\x84\xda\x4d\x76\xb0\x6b\xca\xdf\
\x59\xc9\xac\x20\xe7\x35\x61\x0a\x9b\x0f\xc0\xb1\xc1\x30\xc5\x43\
\xbf\x01\x78\x81\xff\x8a\x6d\x6e\x2e\x07\x1a\xb6\xbe\x6e\x91\x7e\
\x99\x26\x0a\xf8\xc2\x04\x79\xb9\x25\x4f\x15\xb0\xd0\x6c\x36\xf7\
\xbc\xc0\xd7\x6d\xe7\x4e\x97\x20\x08\x6e\x88\xc8\x5b\x7b\x07\x50\
\x7e\x03\x57\x0f\x26\xce\x64\xbc\x00\xdc\xba\x6e\xb2\x83\xfe\x4f\
\x40\x12\x76\x60\x42\x60\x8c\xb1\x6d\xb7\x23\x01\x62\x2f\x18\x03\
\xc6\xe1\x4a\xa5\x42\x18\x86\x4c\x4c\x4e\xf2\xea\xf5\x9b\x77\xc0\
\x11\xf8\x2c\x44\x51\x24\xdd\x6e\x57\xfa\xfd\xbe\xc4\x71\x2c\x83\
\xc1\x40\x86\xc3\xa1\x18\x63\xec\xbb\x58\x2c\xda\xf7\xfd\x8d\x8d\
\x13\x60\x4a\x44\x70\xc5\x0a\x3a\x9d\x3f\x0a\x5a\xad\x96\x94\x4a\
\x25\x59\xcb\xe7\x47\xf0\xb4\x87\xbd\xe0\xfa\x99\xc0\xf4\x7a\xbd\
\x11\x9c\x10\x8c\x52\xaf\x37\xcc\xda\xfa\xfa\xbe\x9f\x9c\xac\x02\
\xce\x01\x59\x40\xf1\xfb\xc4\xc0\x91\x88\xc4\x30\x9e\x9f\xaf\xc9\
\x06\x51\x54\x9d\xd3\x94\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x02\xdf\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\x00\
\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\x01\
\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\
\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\x4d\x50\x4c\x54\
\x45\xff\xff\xff\x59\x59\x59\x5c\x5c\x5c\x80\x80\x80\x83\x83\x83\
\x56\x56\x56\x63\x63\x63\x79\x79\x79\x86\x86\x86\x57\x57\x57\x5e\
\x5e\x5e\x7a\x7a\x7a\x81\x81\x81\x64\x64\x64\x74\x74\x74\x55\x55\
\x55\x64\x64\x64\x74\x74\x74\x84\x84\x84\x53\x53\x53\x66\x66\x66\
\x6f\x6f\x6f\x82\x82\x82\x5b\x5b\x5b\x7f\x7f\x7f\x52\x52\x52\x67\
\x67\x67\x6b\x6b\x6b\x80\x80\x80\x55\x55\x55\x5f\x5f\x5f\x74\x74\
\x74\x7d\x7d\x7d\x52\x52\x52\x54\x54\x54\x58\x58\x58\x5d\x5d\x5d\
\x5f\x5f\x5f\x61\x61\x61\x66\x66\x66\x6a\x6a\x6a\x6b\x6b\x6b\x6d\
\x6d\x6d\x6f\x6f\x6f\x71\x71\x71\x74\x74\x74\x75\x75\x75\x76\x76\
\x76\x77\x77\x77\x79\x79\x79\x7a\x7a\x7a\x80\x80\x80\x81\x81\x81\
\x88\x88\x88\x8f\x8f\x8f\x90\x90\x90\x9c\x9c\x9c\xb8\xb8\xb8\xba\
\xba\xba\xbe\xbe\xbe\xce\xce\xce\xd0\xd0\xd0\xd3\xd3\xd3\xd4\xd4\
\xd4\xd5\xd5\xd5\xd6\x04\x08\xd6\x35\x39\xd9\x06\x09\xd9\xd9\xd9\
\xda\x1f\x22\xda\x45\x48\xdb\xdb\xdb\xdc\x55\x58\xdd\xdd\xdd\xde\
\x37\x3a\xdf\x2d\x30\xdf\x39\x3c\xdf\x3d\x40\xdf\x60\x63\xe1\x08\
\x0a\xe1\x39\x3b\xe2\xe2\xe2\xe3\x1c\x1e\xe7\x0b\x0c\xe7\x39\x3b\
\xe8\xe8\xe8\xe9\xe9\xe9\xea\xea\xea\xeb\x2f\x30\xeb\x9e\xa0\xec\
\x9e\xa0\xec\xec\xec\xed\xa3\xa5\xed\xa8\xaa\xed\xed\xed\xef\xef\
\xef\xf0\xa0\xa1\xf0\xb8\xb9\xf1\xbd\xbf\xf1\xf1\xf1\xf2\xf2\xf2\
\xf3\xf3\xf3\xf5\x0f\x0f\xf6\xf6\xf6\xfa\xfa\xfa\xfb\xfb\xfb\xfc\
\xfa\xfa\xfc\xfc\xfc\xfd\xfd\xfd\xfe\xfa\xfa\xff\xff\xff\x7f\x3d\
\xcd\x14\x00\x00\x00\x21\x74\x52\x4e\x53\x00\x01\x01\x01\x01\x26\
\x26\x26\x26\x71\x71\x71\x71\x80\x80\x81\x81\x81\x81\xb5\xb5\xb5\
\xb5\xb6\xb6\xe7\xe7\xe7\xe7\xf6\xf6\xf6\xf6\x96\x0a\xc3\x45\x00\
\x00\x00\xd7\x49\x44\x41\x54\x18\x19\x05\xc1\xd1\x4e\x83\x30\x18\
\x06\xd0\xaf\xf4\x83\xb6\x38\xe6\x46\x3a\x97\xc5\xc4\xf7\x7f\x21\
\xaf\xbd\xd2\xe0\x2c\x66\x13\x18\x5d\xf9\x59\x3d\x87\x00\x60\x6b\
\x56\x48\x72\x8b\x00\x08\xd0\xfa\x67\x10\x82\x6b\x88\x02\x42\xfb\
\x17\x5a\x6d\x74\x5c\x8a\xed\xf9\x67\x25\xac\x77\xe6\x58\x97\xea\
\x31\xfe\xf5\x7e\x98\x68\xbc\x76\x6f\xae\xd0\xc8\xe5\xc6\x7e\x78\
\x61\xed\x36\xaf\x4e\xcf\x7d\x3a\xec\x74\x1b\xa2\x21\x0b\x65\x39\
\x7f\x56\xba\xcb\x6d\x79\xfa\x35\xac\x8c\x12\x84\xca\x32\x5d\x5b\
\xed\x5c\xc5\x9c\x35\xd5\xa8\xcc\xb6\xd7\x50\x44\x66\x9a\x1b\xc9\
\xc7\x4e\x7a\xd9\x23\xcb\x98\x28\xab\xcc\xce\xab\x8b\xda\x37\x58\
\x3b\xb9\xf3\x96\x2e\xbb\x46\x7b\x0f\x60\x5d\xbe\xd3\x9d\x29\x94\
\xc1\xb6\xa5\x56\x79\x5d\xde\x87\x90\x88\x38\xe6\xe1\x70\x72\x94\
\xee\x6b\x9a\x22\x88\xc7\xd9\xfa\x7b\xf7\xa4\xa6\x45\x42\xcc\x20\
\x90\xe7\xae\xe6\x88\x24\xb7\x05\xc0\x3f\x59\xa3\x6c\xf8\xab\x3b\
\x12\xed\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\xb9\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x02\x36\x49\x44\
\x41\x54\x78\xda\x8d\x93\x4b\x68\x13\x51\x14\x86\xff\x99\xa4\x8d\
\x12\xcd\x22\x2a\x51\x31\xad\xa4\xf5\x85\x56\x11\x44\xa9\x82\x14\
\xb4\x2e\x02\x45\x21\x88\x0b\x37\x82\x1b\xf7\xa2\xa8\x28\xda\xba\
\x93\x22\x92\x16\xb5\x50\x1b\xba\x71\xa1\xb8\xa8\x95\x22\x3e\x16\
\x6e\x8a\x56\xac\x9a\x88\x91\xd0\xa4\xa0\x74\x9c\x49\x9a\x57\xf3\
\xec\x4c\x26\xc7\x7b\xad\x03\xce\x10\x8b\x1f\xfc\x5c\x38\x33\xe7\
\xbb\xe7\x32\x77\x04\x22\x82\x20\x08\x4e\x00\x3e\xfc\x0b\xa7\xc7\
\x81\x03\xe7\x4e\x41\x68\xf6\x42\x2f\x7f\xc7\xc7\xd0\x63\xe4\xa5\
\xaf\x44\x54\xb2\x63\x09\x1f\x11\x85\xd1\x80\x2f\x52\x11\xa7\xef\
\xbc\x81\xbf\xb3\x1d\xfb\x3d\xc0\x94\x02\x4c\x4c\x1d\xba\x10\x7e\
\xf5\xe4\x0c\x80\x51\xf0\x09\x18\x1d\xc4\xf8\x29\xcb\xa4\x24\x53\
\x34\x9f\x4e\x53\x26\x9b\x25\x29\x99\x26\xd7\xc9\x21\x1a\x8f\xa4\
\xa8\xbc\xa8\xd2\xc0\xe0\x20\x65\x72\x0b\x74\xeb\xe1\x24\x89\x3d\
\x03\x45\x1c\xbd\xb7\x42\xc4\x5f\xd8\x6c\x36\x16\x11\xa2\x20\x40\
\x60\x09\x8e\x4d\xc3\xe5\xdb\x82\xae\x36\x17\x6a\x9a\x8a\xf9\x54\
\x0a\x92\x3c\x87\xc0\xc1\x4d\xd8\xb0\x7d\x87\x13\xb6\xfc\x65\x93\
\x40\x14\xc5\xa5\x30\x11\x97\x84\x67\x15\x74\x77\xac\x07\xa0\xa3\
\x50\x2c\x21\x18\x0c\x22\x70\xfc\x04\x8e\x74\x1d\x66\x75\x0f\x2b\
\xab\x7b\xed\xd6\x09\xf8\xce\x5c\x22\x00\xd8\xb8\x6e\x15\xc6\x3f\
\x49\xe8\xef\xf1\xa2\x5c\x2a\x61\x38\x34\x02\xb7\x7b\x0d\xda\xda\
\xb7\x61\xdf\xed\x30\xd0\xa4\xcf\x35\x9e\x80\x49\xb8\xec\xbc\x7f\
\x17\x72\xd5\x2c\xee\xbe\x4e\x40\x27\xa0\xa5\xa5\x15\x0e\x4f\x2b\
\x46\xdf\x29\x48\x16\xd2\x1a\x3e\x3f\xea\x37\x4d\x60\x9c\xdd\x10\
\xf9\x36\x7b\x71\x71\xe7\x7b\xdc\x7c\xfb\x03\xc1\xe7\x45\x1c\xdb\
\xea\xc6\xcb\x99\x38\xf2\xab\x1d\xc0\xe4\xc8\x30\xa4\x68\xc2\x34\
\x81\xc0\x1b\x2d\xb9\x76\x36\x80\xa7\xdd\x2b\xb1\x67\x6d\x06\x1f\
\xa4\x38\x3a\xc5\x6f\x78\xe6\x77\x01\x91\x17\xf7\x89\x61\x5c\x24\
\xfe\x19\xc3\x95\x4a\xc5\x98\x80\xaf\xa6\xfc\x79\x0f\x0c\xe3\xf9\
\x6e\x56\x8b\x98\x8e\xc0\x8a\xcb\x46\xd7\x75\x96\x3a\x2a\xaa\x56\
\x07\xa0\x83\xd1\x50\x60\x95\x71\xf8\x74\xb2\x2c\xc3\xde\xdc\x84\
\xa1\x07\xa1\x09\x00\x51\x30\x4c\x37\xb1\x5a\xad\x92\xaa\xaa\xa4\
\x69\x1a\xd5\x6a\x35\x62\x3b\x52\xbd\x5e\xff\x5d\x8b\xc5\x62\x6c\
\x5d\xa4\xab\x7d\x7d\xd3\xdc\xcf\xfb\x58\xcc\x02\xa3\xd9\x2a\x58\
\x28\x14\x68\x26\x11\xa7\x2b\xbd\xbd\xa6\x66\xb3\x60\x19\x94\x74\
\x4e\xbf\x74\xfd\xc6\x98\xb5\x99\xe7\xff\x7e\x67\x40\x67\x89\x12\
\x03\x16\x7e\x01\x57\xcf\x68\x6a\x5b\x49\x87\x93\x00\x00\x00\x00\
\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x33\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xb0\x49\x44\
\x41\x54\x78\xda\xa5\x93\x3f\x48\xc3\x40\x18\xc5\x5f\xa2\xd8\x74\
\xab\xda\xc1\x3a\xd6\x55\xc4\xcd\x41\x10\xff\xd0\xad\x45\xa1\xe2\
\x24\xae\x8e\xea\xe0\x20\xc5\x4d\xb0\xe8\xac\xb8\xbb\xa8\xb8\xd9\
\xc1\x41\x67\x37\x05\xc7\x42\xc1\x0e\xd6\x52\x41\xcd\x35\x7f\x9a\
\xb6\x97\x78\x5f\x22\xe1\x42\x1d\x0a\x7d\xb9\x7c\x97\xc0\xbd\xdf\
\x3d\xbe\x5c\x14\xcf\xf3\x30\x88\x86\xa9\xe4\xb2\xd9\xef\x56\xcb\
\x49\xec\xec\xed\x43\x96\xa2\x52\x55\xa1\xaa\x0a\x14\x05\x50\x10\
\xdc\xa7\x27\x45\x68\x5a\xec\xe7\xae\x54\x1a\xf5\x01\x96\x69\x25\
\x26\x52\x13\x58\x58\x5c\x82\x27\x03\x80\xc0\x28\x0a\x41\xc4\xf0\
\xe7\xdb\x9b\x2b\x54\x2a\x95\x44\x98\xc0\x75\x5d\x68\x31\x0d\xda\
\xc8\x10\x2e\x1f\x5e\xa3\x29\xfc\x42\x23\x48\xb1\x95\x99\x01\xe7\
\xdc\xf7\x84\x00\x2e\x5e\xba\xdd\xae\xa0\x03\x9b\x2b\xd3\xb4\x3e\
\x4c\x42\x3d\x72\xbd\xbf\x59\x3c\x98\x4e\x87\xd6\xfa\x9e\x48\x02\
\xa2\x36\xed\x36\x99\x43\x79\x01\x81\x06\x5c\x02\x04\x90\xde\x04\
\x2e\xe7\x3e\xd5\x10\x80\xeb\xfb\x27\xc8\x0a\xbf\x12\xa5\x10\x57\
\x3e\x33\x47\x6b\xc9\xd3\x9b\x80\x19\x36\x32\xf3\xb3\xb2\x1b\x9e\
\x64\x26\x56\xd3\x74\xfe\x49\xe0\x72\x70\x41\x3d\xdc\xdd\x46\x9f\
\x22\x8f\xd4\x44\x1e\x34\xb1\x7f\x05\x9e\x68\x0f\x3a\x1d\x90\x8e\
\x8a\xc7\x88\xc7\xe3\x61\x7c\x3a\x03\x24\x8a\xbd\x91\x5f\xf7\xe7\
\xa9\x74\x3a\xda\x83\x8e\xd8\xdd\x69\xb7\x41\x2a\x97\xcb\xb8\x38\
\x3b\x87\x65\x5b\x38\x28\x14\x20\x2b\x35\x39\x89\xda\x47\x8d\x3e\
\x21\x79\x24\x80\xd8\xdd\x71\x1c\x90\x18\x63\x30\x4d\x13\x86\x61\
\x40\xd7\x75\xc8\xf2\x84\xd1\x15\xd1\x93\xc9\x24\xde\xaa\xd5\x48\
\x13\xbf\x18\xd3\xc7\xe8\x34\x32\x9d\xc1\xb6\x6d\x4a\xd4\x03\x20\
\x30\x6d\x66\x5b\x16\xb8\x9c\x40\xe1\x7c\x99\x35\x9b\x8f\xba\xce\
\xc6\x1b\x9f\x0d\xe4\xd6\x56\x41\xaa\xd7\xeb\x90\xf5\x5e\xab\x51\
\x0e\x3c\xbf\xbc\x40\x1d\x52\x7f\x20\x34\xf0\xef\xfc\x0b\xfb\xd2\
\x1e\xf6\x17\x50\x4f\x5c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x02\x63\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
\x00\x00\x09\x70\x48\x59\x73\x00\x00\x6e\xba\x00\x00\x6e\xba\x01\
\xd6\xde\xb1\x17\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd9\x0a\x16\
\x0d\x00\x3a\x08\xf3\xbd\x44\x00\x00\x01\xe3\x49\x44\x41\x54\x78\
\xda\x8d\x92\x3f\x68\x53\x51\x14\xc6\xbf\x73\xef\x7d\x7f\x92\x34\
\x8d\x49\x15\x42\xc5\x14\x8b\x83\xe8\xa6\x4b\x90\x0a\x8a\x4b\x07\
\x09\x0e\x4e\x0e\x42\x10\x5c\x1c\x1d\x9c\x9d\x9c\x05\xd7\x2e\x82\
\x9b\x9b\x19\x3a\x18\x3a\xb4\x81\x88\x8b\x53\x51\x04\x21\x81\x56\
\xa9\x22\xea\x4b\x1a\xfb\x5e\xee\xbb\x9e\xfb\x4c\x87\xa6\xde\xe0\
\x0f\x3e\x1e\x9c\x77\xbe\x73\xbe\xfb\xee\x23\x4c\x28\x16\x8b\x0b\
\x51\x14\xf9\x00\x08\xff\x46\xb3\xf6\x58\x06\x0e\x96\x8c\x03\xad\
\xb5\xe9\x74\x3a\xaf\x00\x9c\x9b\x5e\xa0\xae\x3f\xf9\x68\x46\x31\
\x10\xb1\x18\xd3\xed\x76\x49\x4a\x09\x36\xa1\x5e\xaf\xc3\xd2\x6a\
\xb5\xd0\x68\x34\x6e\x6e\x6e\x6d\xd1\xd5\x95\x95\xfb\x00\x76\x31\
\x81\xea\x8f\x3f\xc4\x6b\xf7\xce\x78\xa3\x38\xc5\xe5\xb3\x85\x23\
\x91\x78\x39\x88\x08\xfd\x7e\x1f\xb5\x5a\x0d\x96\x17\x6f\x06\x78\
\xba\xfe\x19\x4a\x12\x42\x05\x28\x41\xa0\xde\xd7\x03\x0c\x0e\xfe\
\x0e\xe0\x04\x98\x4e\xd0\x6e\xb7\x51\x2a\x95\x10\x04\x01\xee\xac\
\xde\x40\xd9\x3f\x85\x62\x28\xf1\xe8\x25\x0f\x02\x81\x86\xb1\xc6\
\x90\x13\x30\xd6\x74\x2c\x41\xb3\xd9\x3c\x92\x6c\x6f\x10\x61\x94\
\x68\x10\x01\x0a\xb0\x4f\xc2\x84\xe9\x04\xce\xda\xa1\x47\x09\x12\
\x94\x0f\xf8\x25\x70\x2c\x01\x1c\x35\xdb\x9f\x63\xb1\x17\xb4\xfc\
\x60\xc3\xfc\xdc\x4f\x80\x78\x1f\x03\xed\xf1\x26\xe5\xbc\x68\x62\
\x69\x3d\xc6\x9c\xe4\x7e\x3f\x8f\x52\xde\x83\x22\x21\xc7\x0f\x6f\
\x5d\x54\x5f\x76\x7a\xb8\xbb\x7a\x01\xdf\x87\xda\xf9\x27\x19\x56\
\xa5\x20\xf1\x7c\x7d\x1b\xd5\xd3\x4b\x58\x7b\xfd\x7e\xac\x0a\xa1\
\x4f\xbf\x46\x09\xde\xf5\x87\xb8\xf6\xed\x37\x76\x7f\x68\x08\xc7\
\x80\x94\xb5\x78\x42\x66\xbd\x57\x2a\x09\xac\x57\x85\x81\x4f\x9e\
\x12\x3c\x59\x21\xf4\x88\x8b\x12\x44\x8e\x04\x06\xb6\x27\xeb\xb5\
\x1e\xf6\x66\x03\xb0\x30\xef\x63\xb1\x1c\x60\x3e\x27\xf8\x7e\x69\
\xe6\x37\x20\x32\xb6\x37\xf3\x58\xaf\x0a\x7d\x45\xb5\x93\x39\xcc\
\x89\x2a\xde\x6e\xef\x40\x08\x81\x59\xa4\x69\x8a\x4b\xe7\xab\xa8\
\x54\x72\xb0\x5e\xba\xfd\xac\x67\x12\x73\x18\x9b\xf0\x7f\x98\xec\
\x38\x1e\xe9\xcc\x51\x66\x2d\xcf\x74\xbb\x2f\xe5\xd3\x1f\x03\xf5\
\xc1\x56\xb6\x09\x0d\x58\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x03\x22\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\
\x06\xec\x01\x1e\x75\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
\xd8\x01\x03\x12\x35\x13\x24\x41\x46\xca\x00\x00\x02\xaf\x49\x44\
\x41\x54\x38\xcb\x95\x92\x59\x48\x54\x61\x18\x86\xdf\xff\xec\xce\
\x9c\x99\xd1\x99\xb1\x74\x74\x5c\xa6\x2c\x4b\xa4\xdd\x68\xca\x16\
\x2c\x83\x0a\x8c\x24\x8d\x16\x23\x91\x08\xea\x22\xc2\xa0\x20\x8a\
\x0a\x82\xa0\xe8\x22\x22\x28\x93\x2e\x0a\xb2\x81\x88\x92\xd2\x8b\
\xa0\x05\x53\x88\x2e\x24\xb2\xc5\x2c\x4b\x31\x9d\xc5\xd4\x59\xce\
\xcc\x59\xfe\xd3\x55\x51\x12\xa1\xdf\xed\xc3\xfb\xf0\xf1\x7d\x2f\
\x30\x85\x79\x7c\xfb\xfc\xc1\x47\x4d\xc7\xdf\x6e\xa9\x58\xc1\x4c\
\x66\xcc\x54\x04\x7a\x2a\xd6\xe0\x74\xb9\xba\x5b\x9f\x74\xd2\x69\
\x0b\x9e\x3d\xbc\x5e\x26\x30\xe6\x42\x03\x7c\xd3\xbf\xf8\x7f\x05\
\x17\x8f\xed\x75\x06\x87\xbf\x9f\x83\x69\x7e\x6a\x6e\x69\x7f\x3a\
\x2d\x41\xf5\xfa\xa5\x2c\x2f\x8a\x87\x48\x3c\x5c\xf1\xb9\x7f\xb8\
\xe7\xc6\x9d\x47\x74\xca\x82\x8b\x47\xb7\xbb\x76\x56\xf9\xbb\xe6\
\xe4\x65\x9c\x8e\xc6\x53\x60\x23\x51\xf1\x1e\xc0\xfd\xe2\xf7\x08\
\xc9\x7a\xe0\xf7\xaf\x07\x00\x76\x72\xb8\xa4\x04\xa8\x58\xba\xec\
\xbe\xc7\x93\x5d\xae\xa8\x3a\x58\x35\x0a\x97\x68\xc9\x11\x83\xb1\
\x9c\xd5\xa1\x48\x5b\x35\x30\xb3\x60\xed\xca\xbb\xb3\x16\x2d\xd8\
\x53\xde\xd3\x33\xc0\x4d\x16\xec\xab\xaa\xaf\xb5\xdb\xd2\x2a\x95\
\x44\x1c\x48\xa5\x40\xa9\x0e\xaa\xe8\xa6\xaf\xbc\x7c\x53\x77\x52\
\x69\x2a\x74\xbb\x66\xcf\x98\x5b\x92\x67\x1a\x26\x84\x1c\xcf\x66\
\xf2\x67\xf8\xcc\x81\x8d\xb2\x35\x4d\xec\x9e\x91\x5b\xe0\x63\x08\
\x80\x78\x04\x0c\xcb\x40\xfa\x18\x1c\xcb\x1d\x50\xa3\x9a\xc4\x43\
\xe2\x04\xc0\x92\x86\xbe\xae\x8e\x8e\x1f\x5f\x86\xea\xff\xda\x20\
\xd3\x21\x5d\xb3\xd8\x6c\x3e\x99\xd3\x10\x1e\x1d\x47\x22\xa1\x41\
\x07\x01\xf3\x2d\x74\x55\x0c\x46\x76\x8b\x43\x51\x28\x02\x8f\x11\
\x49\x1f\x0b\xf6\x47\xf6\x1f\x06\x94\xdf\x37\xb8\x79\x72\xdb\x51\
\x30\xec\x91\xcc\x0c\x3b\x26\xc6\xa2\xd0\xd4\x24\x5c\x32\x07\x81\
\x67\x20\xbf\xfa\x30\xd3\x37\x18\x16\x34\x9e\x10\xdb\x44\x0c\x6e\
\x40\x0a\xd9\xac\x85\xcb\xe3\xc9\x36\x16\x00\x9a\x4f\x6c\xdd\x91\
\xe9\x94\xaf\x24\x12\x3a\x03\x6a\xc0\x2a\x71\xd0\x35\x15\x76\xbb\
\x05\x9a\xaa\x9b\x65\xef\x87\xa8\x91\x6e\x67\x6e\x39\xac\x3d\x23\
\xe9\x0e\x7e\x4d\x70\x5c\x2a\x10\x85\xa2\x89\xe2\xe2\x02\xe6\x54\
\xfd\xba\xc5\xb2\x55\x6c\xec\xfd\x1a\xe2\xf2\xb2\x1d\xa6\x95\x63\
\xa1\xa8\x29\x64\xbb\x6d\x00\x28\x32\x24\x9e\xc6\xf3\x3c\x4c\xbb\
\xd3\xfe\xae\xac\xb2\xf4\xf8\xa8\x84\x86\xb6\x7c\x6f\x38\xe9\x72\
\x23\x34\x38\xf8\x86\x9b\x5f\xe4\x9d\x00\x54\x5a\x9a\xef\x31\x19\
\x83\x42\x92\x58\x83\x81\xc8\x5a\x25\x16\x34\x09\xf0\x92\xf0\xb6\
\x93\xd3\xbb\xbc\x7e\x5f\x93\xc5\x29\xf7\x6e\xd8\xb5\x2a\xda\x77\
\xf9\x45\x6d\x6b\x38\xbc\xb8\x71\x7c\xbc\x85\x04\x2e\xd4\x59\xa8\
\x61\xf8\x89\x89\x6a\x01\xc4\xc7\x89\xc4\x2b\xf0\x4c\x2e\x55\x35\
\x19\x94\x4d\xa9\x2c\xdb\x6c\x18\xe4\xac\xa6\x93\x70\xe0\x75\x54\
\x0f\x04\x02\x7f\xbd\x9d\x00\x40\xeb\xa5\x3a\xd6\xa4\x44\x34\x28\
\xb1\x9b\x84\x7a\x35\x83\xce\x8b\xc7\xe2\xb3\xb2\x1c\xb2\xd2\x1b\
\x52\x9e\x67\x2d\x21\x2f\x6b\x6a\x02\xff\xac\xfc\x4f\x89\x4f\x0d\
\x65\xb8\x03\x8d\x9c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\
\x82\
\x00\x00\x01\xf3\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x04\x00\x00\x00\xb5\xfa\x37\xea\
\x00\x00\x00\x02\x73\x42\x49\x54\x08\x08\x55\xec\x46\x04\x00\x00\
\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\x01\x3a\
\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\x77\
\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\
\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\x72\x49\x44\x41\x54\
\x28\xcf\x45\x91\x4f\x2b\x04\x71\x1c\xc6\xbf\xf3\x32\xe4\x6c\xde\
\x80\xa2\x44\x39\xbb\xec\x1f\xb3\x23\x6d\x9b\x25\x8b\x10\xfd\x76\
\x36\xec\xa2\x31\x89\x13\x0e\x2e\xca\xfb\x98\x4d\x7b\xf0\x12\xb4\
\x85\x83\x36\x17\x97\xb1\xa2\xe9\x47\xfd\x0e\x63\xb6\x8f\x83\xb5\
\x9e\xe7\xf6\xf4\xf4\x1c\x9e\x8f\x20\xbf\x3e\xb1\x8f\x83\x20\xf4\
\x23\x3f\x0a\xc2\xe3\xe0\xc4\xfe\xcb\x05\x41\x7c\xeb\x50\xd5\x4d\
\x95\x1a\x3e\x3e\x35\xaa\xd4\xcd\xa1\xf2\xad\x7e\xa1\x61\xd5\x9b\
\xdb\xec\xd2\xa2\xcd\x13\x1d\x1e\x68\xb1\xc3\x36\xf5\x66\xc3\x42\
\x04\xf1\xd4\x06\x17\xdc\xf3\x4a\xcc\x27\x5f\x68\xde\x78\xe6\x9c\
\x0d\x3c\x85\x88\xb2\x37\x8d\xc7\x23\x1f\x18\xbe\xe9\xd1\x23\x25\
\x41\xf3\x42\x8d\x4d\xa3\x6c\x59\x0f\x16\xb9\xe5\x1d\xc3\x15\x67\
\x1c\xa0\xd8\x42\x91\xa2\x69\xb3\xc8\xfa\x91\x54\xc2\x15\xee\xd0\
\xa4\x5c\xd2\xa0\x82\x4b\x8e\x59\x20\xa1\xcb\x1a\x95\x50\xca\x91\
\x47\x9b\x98\x94\x3d\x96\xc9\x31\xc5\x38\xd3\x40\x4a\xcc\x3e\xe5\
\x48\x4a\x51\x95\x47\x34\x3d\xb2\x8c\x32\x84\x30\xc4\x28\xd0\x43\
\x73\x40\x29\x92\x62\x58\xee\x2f\xb8\x4c\x30\xc2\x30\x23\x4c\xf4\
\x17\x96\x29\x86\x52\x0c\x1c\x6e\xe8\x92\xb0\xc4\x0c\x93\x8c\x31\
\xc9\x0c\x90\xd0\xc1\xa1\x78\x24\xf3\x76\xc1\xac\xf2\x8c\x26\xe5\
\x5f\x29\x1a\x8f\x82\x99\xb7\x05\x71\x55\x96\x53\x5e\xd0\x24\xa4\
\x83\x1f\xae\xc9\xe2\x2a\x44\x90\x39\xcb\x6d\x66\x58\xa3\x4d\x97\
\x18\x4d\x4c\x87\x2a\x19\xdc\xe6\x9c\xd5\x87\xe5\x5a\x8e\xca\x9b\
\x0c\x25\x76\xd8\x63\x81\x0c\x79\xe3\x28\xd7\x1a\xd0\x44\x90\x82\
\xed\x04\xf9\x30\x17\xe5\xa2\x7c\xe8\x04\x85\x01\xee\x1f\x8d\x42\
\x66\xb3\xf5\x8b\xfe\x99\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x03\xa3\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x03\x20\x49\x44\
\x41\x54\x78\xda\x6d\x93\xcd\x6b\x5c\x55\x18\xc6\x9f\xf7\xdc\x73\
\xee\xd7\x24\x33\x49\x27\xa9\x49\x27\xa1\x4d\x86\xd6\x18\x34\x4e\
\x28\xad\x8d\x42\x68\xfd\xa0\xd0\xa2\xfe\x01\x45\xb0\xb8\x75\xa3\
\xe0\xd2\x55\x45\x37\x0a\xba\x13\x37\x82\x3b\x17\x12\x14\x14\x8d\
\x45\x51\x6a\x21\x15\xa3\x26\x25\xc1\x8f\x36\x89\x69\xd2\x74\xec\
\x24\x73\x33\x9d\xfb\x71\xce\x3d\xf7\x78\x47\x0c\x66\xd1\x1f\x3c\
\xbb\xf3\xbc\xe7\xe5\x79\xdf\x97\x8c\x31\xd8\x0f\x3d\x47\x55\x30\
\x5c\xb0\xba\xac\x27\x47\x2a\x23\x93\xe5\xae\x32\x5b\xd9\x5c\x59\
\xaa\x6f\xd5\x2f\x43\xe3\x43\xf3\x99\xf9\xf3\xbf\x77\x43\x00\x78\
\xa7\xc0\x9e\x91\x81\xf0\x4a\x79\xb4\xfc\xc6\xf9\x13\xe7\xdd\x4a\
\x7f\x05\x83\x7d\x83\xb0\x98\x85\x20\x08\x70\xe3\xf6\x0d\xcc\x5c\
\x9d\x89\xb7\xd7\xb6\x2f\x21\xc3\x8f\xa5\x4a\xf1\x93\x24\x48\xe2\
\x4e\x81\x7f\xcd\xcc\xa1\x6f\xa7\x4e\x9d\x9a\x3a\x33\xf9\x94\x60\
\x36\xc3\xfd\xd0\x52\xe3\xea\xc2\x15\xf5\xeb\xfa\x2f\x74\xf1\xe9\
\x97\xf8\x7b\x1f\xbf\x0b\x8e\x1c\x62\x78\xb5\x36\xf6\xf0\xd4\x89\
\xb1\xc7\x44\x10\x06\xa0\x90\xd0\x68\x34\xb0\x71\x7b\x03\x64\x08\
\xd5\xe1\x2a\xbc\x1e\x0f\x1d\x26\x8e\xd6\xc4\x44\xb5\x86\xcc\x18\
\x30\x10\x78\xfe\xfb\x83\xfd\x03\x3d\x97\x8e\x1e\x19\x17\x8d\x66\
\x03\x3a\xd5\x98\xff\x79\x1e\x7f\xac\xfc\x0e\x47\x0b\x78\xb6\x87\
\x2b\x73\xdf\xa3\xb7\x52\xc6\xc9\xe3\x27\xd1\x5b\xec\x05\x0c\x60\
\x19\x0b\x8c\x18\x38\x11\x5e\xa8\x94\x86\x9c\x76\xdc\x46\x47\x8b\
\xd7\x17\xf1\x77\x7d\xd3\x14\x5c\x21\x43\xa9\x2e\x27\x99\xd2\x3e\
\x13\x67\x9b\x71\xc3\x9e\x5d\x9d\xa5\xe9\xf1\x69\xb8\xc6\x05\x49\
\x82\x45\x04\xee\xf8\xe2\x8c\xd1\xa0\xed\xe6\x36\x76\x83\x5d\x6c\
\xdc\x5a\x87\xef\x8b\x68\x37\x4a\x1e\xed\x24\x9e\x77\x38\x09\x0b\
\xcf\x98\x47\x88\x1e\x38\x7c\x10\x2d\xde\x42\x74\x2f\x42\xb0\x13\
\x80\x32\x18\x2e\x1c\x56\x8b\xb5\x42\x1a\x04\xa8\xdf\xad\xc3\xd2\
\x0c\x6d\xa9\xbe\xde\x1b\x57\x97\xe7\xf6\x89\x22\xf3\x44\xaf\x87\
\xf4\x4e\x82\xb5\xe0\x26\x5a\x77\x5a\x30\xed\x0c\x69\xac\xbf\x24\
\xff\x82\x90\x59\xdb\x12\xe0\x80\x72\x14\x84\x22\x48\xa9\x67\xf5\
\x4c\x76\x76\xdf\x6e\xb8\x00\x4a\x02\x16\x81\x8c\xce\x72\x69\x63\
\x94\xf9\xd4\xb4\x98\x4c\xf4\x35\x84\x29\x62\x11\x43\x97\x35\xcc\
\x28\xe0\xb8\xd6\x74\x27\x5c\xfc\xcf\x21\x46\xf4\x11\x4d\x50\x9f\
\xae\x65\x5c\x0c\x5b\xaa\xbb\xe8\xc4\xc8\xe1\xa9\xcc\xbe\x70\x6d\
\xf1\x38\x0e\xa4\x84\x3e\x20\xeb\xce\x50\x2e\x0a\x87\x96\xd8\x4f\
\xec\x79\xfa\x1c\x44\xe4\xd8\xfc\x5c\x69\xd8\x9d\x4b\x87\xb2\xd3\
\x89\xa2\xd5\xb8\x94\x6e\x5a\xcb\x6c\x8b\x2e\xd2\x26\xe1\x59\x3c\
\xe4\xb9\x62\x1e\x23\x70\xe5\x40\x0a\x5f\xd8\x28\x38\x36\xca\xdc\
\x87\x6a\x68\x63\x81\xe0\x0d\xf0\x34\xa4\xf4\xaf\x58\xa5\x8b\xa1\
\x94\xcb\xaa\x95\xad\x45\xbf\xa9\xaf\xa2\x0f\xd4\x2a\xcb\xc3\x5a\
\x8e\x62\xf5\xba\xbf\x23\x94\xcb\x3b\x73\xe7\x79\x01\x01\xee\x13\
\x0a\xc7\x6c\xb2\x26\x18\xc9\xfe\x4c\x14\x7c\xbb\xda\xe5\xd8\xe3\
\x25\xdb\x1f\x4b\x16\xf4\x6b\xf1\x56\x7a\x04\x39\x7b\x3b\xfb\x4e\
\x63\x2b\xfc\xa6\xe7\xa6\x9b\xf4\x30\x0f\xae\x10\xa0\x02\x61\xf7\
\x60\x8c\x9d\x43\x11\x9a\x83\x31\x5a\xfd\x09\x8a\xdc\xa9\x46\xd7\
\xe5\xe9\xb0\x29\x97\x00\x7c\x87\x9c\xfd\xc7\x44\x00\x5e\xee\x3e\
\xe0\xbe\xe5\x8d\x72\xaf\x32\x56\x64\xf1\xb1\x14\xed\xb2\x84\x75\
\x8b\xe1\xee\x5c\xdb\xe8\x6b\x59\x18\xde\x53\x6f\x02\x78\x3b\xef\
\x5c\x22\xe7\x7e\xe7\x7c\x18\xc0\x8b\xb9\x9e\xb0\x18\x1d\x37\x06\
\x94\x19\xb3\x00\xe0\x87\x5c\xef\xe7\xc6\x75\xec\xe3\x1f\x51\x72\
\x6b\x1e\x49\x70\xdf\x2c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x01\xe5\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
\x00\x00\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\
\x1e\x75\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x03\x14\
\x12\x23\x3b\xba\x62\x67\xa1\x00\x00\x01\x65\x49\x44\x41\x54\x78\
\xda\x95\x90\xcf\x4a\xc3\x40\x10\xc6\x67\x37\xa6\xa5\x81\x5e\x8a\
\xa7\x3c\x86\x78\xf1\x01\xd4\x1e\xac\x6f\xe0\xc5\x73\xbd\xd8\x53\
\x2d\xf8\x08\xbe\x4b\xcf\x3e\x80\xa0\x10\x3c\xfb\x00\x56\xda\x54\
\x4a\x82\x25\x7f\x77\x3a\xb3\x6c\xe8\x9a\x90\xa2\x1f\x7c\x7c\xbb\
\xec\xcc\x6f\x77\x56\x00\xc0\x80\x7c\x46\x16\x70\x58\x48\x7e\x21\
\x7f\x43\x4d\x57\xf8\x37\x31\x60\x04\x35\x1d\x55\x37\xaf\xc2\x10\
\xa4\x94\x20\x85\x00\x41\x29\x38\xd9\xa6\xb0\xdf\xef\x73\x88\x26\
\xc0\xc8\x71\x1c\x0d\x88\xa3\x08\x82\x20\x00\x2d\x0b\xd0\xed\x76\
\x39\x4e\xc8\xa9\x35\xd2\x2b\x2f\x46\x48\xda\x6c\x36\x18\xc5\x31\
\xce\xe7\x73\xfc\xc7\x48\xc3\xc6\x0b\xf8\x56\x56\xb8\x5e\x83\xc3\
\x23\x19\x0b\xb2\x3d\x92\xe7\x79\x1c\xb2\x02\xe8\x22\x0d\x31\x00\
\xdd\x4c\x7b\x9d\x55\x33\x67\xdb\x1f\x48\xab\xd0\xec\xf7\x10\xeb\
\x53\xa1\x15\x60\x15\xd9\x40\xa7\x06\xa6\x6c\x00\xea\x07\x36\x60\
\x0f\x3e\x0c\x68\x42\x44\xad\xb9\x28\x0a\x08\xc3\x10\x3a\x1d\x17\
\x7a\x3d\x0f\x14\x08\xa4\xb2\x82\x01\x8a\x0e\xd1\x75\x5d\x51\xdd\
\xac\xb3\x76\x2b\x37\xfb\xbe\x0f\xac\xed\xf6\x07\x1e\x67\xb3\x67\
\x5a\x06\xbc\x3f\x26\xdf\x90\x6f\x8d\x9f\x90\x94\x24\x09\x66\x59\
\x86\x0c\x2f\xcb\x12\x17\x5f\x0b\x54\x4a\x61\x1c\xc7\x38\xbe\x1b\
\xbf\x51\xdd\x29\xb4\x68\xc8\x80\x34\x4d\x31\xcf\x73\x06\xe8\xc6\
\xe5\x6a\xa9\x9b\x27\x93\xfb\x77\xaa\xb9\x26\xcb\x36\xc0\x05\x35\
\x2a\xb4\x94\x15\x25\x7e\x2e\x57\x38\x7d\x98\xf2\x93\x2f\x7f\x7d\
\x3e\x34\x35\x20\x9f\x9b\x22\x5b\x68\x66\xfe\x20\x2b\x30\xda\x01\
\x68\x0b\xe8\x88\x71\x7b\x2b\x7d\x00\x00\x00\x00\x49\x45\x4e\x44\
\xae\x42\x60\x82\
"
qt_resource_name = "\
@ -54,16 +530,82 @@ qt_resource_name = "\
\x07\xac\xfa\xc2\
\x00\x74\
\x00\x65\x00\x78\x00\x74\x00\x65\x00\x72\
\x00\x06\
\x07\x03\x7d\xc3\
\x00\x69\
\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\
\x00\x08\
\x0a\x61\x5a\xa7\
\x00\x69\
\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x15\
\x0f\x21\xb3\x87\
\x00\x67\
\x00\x6f\x00\x2d\x00\x6e\x00\x65\x00\x78\x00\x74\x00\x2d\x00\x76\x00\x69\x00\x65\x00\x77\x00\x2d\x00\x70\x00\x61\x00\x67\x00\x65\
\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x19\
\x0d\x16\x46\x27\
\x00\x67\
\x00\x6f\x00\x2d\x00\x70\x00\x72\x00\x65\x00\x76\x00\x69\x00\x6f\x00\x75\x00\x73\x00\x2d\x00\x76\x00\x69\x00\x65\x00\x77\x00\x2d\
\x00\x70\x00\x61\x00\x67\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x10\
\x0c\xbc\x2e\x67\
\x00\x64\
\x00\x6f\x00\x63\x00\x75\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x2d\x00\x6e\x00\x65\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x10\
\x08\x12\xae\xa7\
\x00\x6d\
\x00\x65\x00\x64\x00\x69\x00\x61\x00\x2d\x00\x72\x00\x65\x00\x63\x00\x6f\x00\x72\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x18\
\x00\x8c\x38\x27\
\x00\x64\
\x00\x6f\x00\x63\x00\x75\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x2d\x00\x6f\x00\x70\x00\x65\x00\x6e\x00\x2d\x00\x72\x00\x65\x00\x63\
\x00\x65\x00\x6e\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x11\
\x0f\xe3\xd5\x67\
\x00\x64\
\x00\x6f\x00\x63\x00\x75\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x2d\x00\x73\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\
\x00\x16\
\x04\x98\x82\x67\
\x00\x64\
\x00\x6f\x00\x63\x00\x75\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x2d\x00\x6f\x00\x70\x00\x65\x00\x6e\x00\x2d\x00\x64\x00\x61\x00\x74\
\x00\x61\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x0e\
\x0d\x8b\x39\xe7\
\x00\x65\
\x00\x64\x00\x69\x00\x74\x00\x2d\x00\x63\x00\x6c\x00\x65\x00\x61\x00\x72\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x17\
\x09\x10\x6a\x47\
\x00\x6d\
\x00\x65\x00\x64\x00\x69\x00\x61\x00\x2d\x00\x70\x00\x6c\x00\x61\x00\x79\x00\x62\x00\x61\x00\x63\x00\x6b\x00\x2d\x00\x73\x00\x74\
\x00\x6f\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x10\
\x08\x15\x13\x67\
\x00\x76\
\x00\x69\x00\x65\x00\x77\x00\x2d\x00\x72\x00\x65\x00\x66\x00\x72\x00\x65\x00\x73\x00\x68\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x0d\
\x01\x1c\xb1\xa7\
\x00\x65\
\x00\x64\x00\x69\x00\x74\x00\x2d\x00\x63\x00\x6f\x00\x70\x00\x79\x00\x2e\x00\x70\x00\x6e\x00\x67\
"
qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\
\x00\x00\x00\x12\x00\x02\x00\x00\x00\x0b\x00\x00\x00\x04\
\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x4b\
\x00\x00\x01\xfa\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x6a\
\x00\x00\x01\x4c\x00\x00\x00\x00\x00\x01\x00\x00\x11\x3f\
\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x09\x68\
\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x18\xc3\
\x00\x00\x01\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x16\xcc\
\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x07\x21\
\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x04\xb3\
\x00\x00\x01\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x13\xa6\
\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x02\x30\
\x00\x00\x01\x24\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x08\
"
def qInitResources():

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'texter3.ui'
# Form implementation generated from reading ui file 'texter.ui'
#
# Created: Mon Apr 21 22:38:51 2014
# Created: Sat May 10 18:57:19 2014
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!
@ -26,7 +26,7 @@ except AttributeError:
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(1475, 651)
MainWindow.resize(1475, 592)
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -47,6 +47,11 @@ class Ui_MainWindow(object):
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
MainWindow.setPalette(palette)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Helvetica"))
font.setPointSize(8)
font.setBold(True)
MainWindow.setFont(font)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/texter/icon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
MainWindow.setWindowIcon(icon)
@ -57,8 +62,8 @@ class Ui_MainWindow(object):
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.live_text = KRichTextWidget(self.centralwidget)
self.live_text.setMinimumSize(QtCore.QSize(775, 582))
self.live_text.setMaximumSize(QtCore.QSize(775, 582))
self.live_text.setMinimumSize(QtCore.QSize(778, 586))
self.live_text.setMaximumSize(QtCore.QSize(778, 586))
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -102,7 +107,7 @@ class Ui_MainWindow(object):
self.live_text.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.live_text.setAcceptRichText(True)
self.live_text.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByKeyboard|QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextBrowserInteraction|QtCore.Qt.TextEditable|QtCore.Qt.TextEditorInteraction|QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse)
self.live_text.setRichTextSupport(KRichTextWidget.RichTextSupportValues(KRichTextWidget.SupportAlignment|KRichTextWidget.SupportChangeListStyle|KRichTextWidget.SupportFontFamily|KRichTextWidget.SupportFontSize|KRichTextWidget.SupportTextForegroundColor))
self.live_text.setRichTextSupport(KRichTextWidget.RichTextSupportValues(KRichTextWidget.SupportAlignment|KRichTextWidget.SupportFontFamily|KRichTextWidget.SupportFontSize|KRichTextWidget.SupportTextForegroundColor))
self.live_text.setObjectName(_fromUtf8("live_text"))
self.horizontalLayout.addWidget(self.live_text)
self.preview_text = KRichTextWidget(self.centralwidget)
@ -111,8 +116,8 @@ class Ui_MainWindow(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.preview_text.sizePolicy().hasHeightForWidth())
self.preview_text.setSizePolicy(sizePolicy)
self.preview_text.setMinimumSize(QtCore.QSize(300, 582))
self.preview_text.setMaximumSize(QtCore.QSize(769, 582))
self.preview_text.setMinimumSize(QtCore.QSize(300, 586))
self.preview_text.setMaximumSize(QtCore.QSize(778, 586))
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -140,11 +145,7 @@ class Ui_MainWindow(object):
self.preview_text.setRichTextSupport(KRichTextWidget.RichTextSupportValues(KRichTextWidget.SupportAlignment|KRichTextWidget.SupportChangeListStyle|KRichTextWidget.SupportFontFamily|KRichTextWidget.SupportFontSize|KRichTextWidget.SupportTextForegroundColor))
self.preview_text.setObjectName(_fromUtf8("preview_text"))
self.horizontalLayout.addWidget(self.preview_text)
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout.addLayout(self.horizontalLayout)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)