forked from openlp/openlp
Merge ThemeManager changes to Import Themes
Changes to Render.py Addition of ThemeXML Code. Summary https://code.launchpad.net/~trb143/openlp/ThemeManager/+merge/5014 bzr-revno: 428
This commit is contained in:
commit
9bdafd5659
@ -31,7 +31,9 @@ from serviceitem import ServiceItem
|
||||
from toolbar import OpenLPToolbar
|
||||
from songxmlhandler import SongXMLBuilder
|
||||
from songxmlhandler import SongXMLParser
|
||||
from themexmlhandler import ThemeXMLBuilder
|
||||
from themexmlhandler import ThemeXMLParser
|
||||
|
||||
__all__ = ['PluginConfig', 'Plugin', 'SettingsTab', 'MediaManagerItem', 'Event', 'EventType'
|
||||
'XmlRootClass', 'ServiceItem', 'Receiver', 'OpenLPToolbar', 'SongXMLBuilder',
|
||||
'SongXMLParser', 'EventManager']
|
||||
'XmlRootClass', 'ServiceItem', 'Receiver', 'OpenLPToolbar', 'SongXMLBuilder',
|
||||
'SongXMLParser', 'EventManager', 'ThemeXMLBuilder', 'ThemeXMLParser']
|
||||
|
118
openlp/core/lib/themexmlhandler.py
Normal file
118
openlp/core/lib/themexmlhandler.py
Normal file
@ -0,0 +1,118 @@
|
||||
from xml.dom.minidom import Document
|
||||
from xml.etree.ElementTree import ElementTree, XML, dump
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<song version="1.0">
|
||||
<lyrics language="en">
|
||||
<verse type="chorus" label="1">
|
||||
<![CDATA[ ... ]]>
|
||||
</verse>
|
||||
</lyrics>
|
||||
</song>
|
||||
|
||||
"""
|
||||
class ThemeXMLBuilder():
|
||||
def __init__(self):
|
||||
# Create the minidom document
|
||||
self.theme_xml = Document()
|
||||
|
||||
def new_document(self, name):
|
||||
# Create the <song> base element
|
||||
self.theme = self.theme_xml.createElement(u'Theme')
|
||||
self.theme_xml.appendChild(self.theme)
|
||||
self.theme.setAttribute(u'version', u'1.0')
|
||||
|
||||
self.name = self.theme_xml.createElement(u'Name')
|
||||
ctn = self.theme_xml.createTextNode(name)
|
||||
self.name.appendChild(ctn)
|
||||
self.theme.appendChild(self.name)
|
||||
|
||||
def add_background_transparent(self):
|
||||
# Create the main <lyrics> element
|
||||
background = self.theme_xml.createElement(u'Background')
|
||||
background.setAttribute(u'mode', u'transparent')
|
||||
self.theme.appendChild(background)
|
||||
|
||||
def add_background_solid(self, bkcolor):
|
||||
background = self.theme_xml.createElement(u'Background')
|
||||
background.setAttribute(u'mode', u'opaque')
|
||||
background.setAttribute(u'type', u'solid')
|
||||
self.theme.appendChild(background)
|
||||
|
||||
color = self.theme_xml.createElement(u'color')
|
||||
bkc = self.theme_xml.createTextNode(bkcolor)
|
||||
color.appendChild(bkc)
|
||||
background.appendChild(color)
|
||||
|
||||
def add_background_gradient(self, startcolor, endcolor):
|
||||
background = self.theme_xml.createElement(u'Background')
|
||||
background.setAttribute(u'mode', u'opaque')
|
||||
background.setAttribute(u'type', u'gradient')
|
||||
self.theme.appendChild(background)
|
||||
|
||||
color = self.theme_xml.createElement(u'startcolor')
|
||||
bkc = self.theme_xml.createTextNode(startcolor)
|
||||
color.appendChild(bkc)
|
||||
background.appendChild(color)
|
||||
|
||||
color = self.theme_xml.createElement(u'endcolor')
|
||||
bkc = self.theme_xml.createTextNode(endcolor)
|
||||
color.appendChild(bkc)
|
||||
background.appendChild(color)
|
||||
|
||||
def add_background_image(self, filename, bordercolor):
|
||||
background = self.theme_xml.createElement(u'Background')
|
||||
background.setAttribute(u'mode', u'opaque')
|
||||
background.setAttribute(u'type', u'image')
|
||||
self.theme.appendChild(background)
|
||||
|
||||
color = self.theme_xml.createElement(u'filename')
|
||||
bkc = self.theme_xml.createCDATASection(filename)
|
||||
color.appendChild(bkc)
|
||||
background.appendChild(color)
|
||||
|
||||
color = self.theme_xml.createElement(u'bordercolor')
|
||||
bkc = self.theme_xml.createTextNode(bordercolor)
|
||||
color.appendChild(bkc)
|
||||
background.appendChild(color)
|
||||
|
||||
|
||||
def add_verse_to_lyrics(self, type, number, content):
|
||||
"""
|
||||
type - type of verse (Chorus, Verse , Bridge, Custom etc
|
||||
number - number of item eg verse 1
|
||||
content - the text to be stored
|
||||
"""
|
||||
verse = self.theme_xml.createElement(u'verse')
|
||||
verse.setAttribute(u'type', type)
|
||||
verse.setAttribute(u'label', number)
|
||||
self.lyrics.appendChild(verse)
|
||||
|
||||
# add data as a CDATA section
|
||||
cds = self.theme_xml.createCDATASection(content)
|
||||
verse.appendChild(cds)
|
||||
|
||||
def dump_xml(self):
|
||||
# Debugging aid to see what we have
|
||||
print self.theme_xml.toprettyxml(indent=" ")
|
||||
|
||||
def extract_xml(self):
|
||||
# Print our newly created XML
|
||||
return self.theme_xml.toxml()
|
||||
|
||||
class ThemeXMLParser():
|
||||
def __init__(self, xml):
|
||||
self.theme_xml = ElementTree(element=XML(xml))
|
||||
|
||||
def get_verses(self):
|
||||
#return a list of verse's and attributes
|
||||
iter=self.theme_xml.getiterator()
|
||||
verse_list = []
|
||||
for element in iter:
|
||||
if element.tag == u'verse':
|
||||
verse_list.append([element.attrib, element.text])
|
||||
return verse_list
|
||||
|
||||
def dump_xml(self):
|
||||
# Debugging aid to see what we have
|
||||
print dump(self.theme_xml)
|
@ -17,13 +17,19 @@ You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
import logging
|
||||
|
||||
import sys
|
||||
from PyQt4 import QtGui, QtCore, Qt
|
||||
|
||||
from copy import copy
|
||||
from interpolate import interpolate
|
||||
|
||||
class Renderer:
|
||||
|
||||
global log
|
||||
log=logging.getLogger(u'Renderer')
|
||||
log.info(u'Renderer Loaded')
|
||||
"""All the functions for rendering a set of words onto a Device Context
|
||||
|
||||
How to use:
|
||||
@ -44,21 +50,21 @@ class Renderer:
|
||||
self._theme=None
|
||||
self._bg_image_filename=None
|
||||
self._paint=None
|
||||
|
||||
|
||||
def set_debug(self, debug):
|
||||
self._debug=debug
|
||||
|
||||
|
||||
def set_theme(self, theme):
|
||||
self._theme=theme
|
||||
if theme.BackgroundType == 2:
|
||||
self.set_bg_image(theme.BackgroundParameter1)
|
||||
|
||||
def set_bg_image(self, filename):
|
||||
print "set bg image", filename
|
||||
log.debug(u"set bg image %s", filename)
|
||||
self._bg_image_filename=filename
|
||||
if self._paint is not None:
|
||||
self.scale_bg_image()
|
||||
|
||||
|
||||
def scale_bg_image(self):
|
||||
assert self._paint
|
||||
i=QtGui.QImage(self._bg_image_filename)
|
||||
@ -67,7 +73,7 @@ class Renderer:
|
||||
dcw=self._paint.width()+1;dch=self._paint.height()
|
||||
imratio=imw/float(imh)
|
||||
dcratio=dcw/float(dch)
|
||||
print "Image scaling params", imw, imh, imratio, dcw, dch, dcratio
|
||||
log.debug(u"Image scaling params %s %s %s %s %s %s", imw, imh, imratio, dcw, dch, dcratio)
|
||||
if imratio > dcratio:
|
||||
scale=dcw/float(imw)
|
||||
elif imratio < dcratio:
|
||||
@ -84,9 +90,9 @@ class Renderer:
|
||||
self._paint=p
|
||||
if self._bg_image_filename is not None:
|
||||
self.scale_bg_image()
|
||||
|
||||
|
||||
def set_words_openlp(self, words):
|
||||
# print "set words openlp", words
|
||||
# log.debug(u" "set words openlp", words
|
||||
verses=[]
|
||||
words=words.replace("\r\n", "\n")
|
||||
verses_text=words.split('\n\n')
|
||||
@ -99,9 +105,9 @@ class Renderer:
|
||||
verses_text.append('\n'.join(v).lstrip()) # remove first \n
|
||||
|
||||
return verses_text
|
||||
|
||||
|
||||
def render_screen(self, screennum):
|
||||
print "render screen\n", screennum, self.words[screennum]
|
||||
log.debug(u"render screen\n %s %s ", screennum, self.words[screennum])
|
||||
import time
|
||||
t=0.0
|
||||
words=self.words[screennum]
|
||||
@ -111,51 +117,45 @@ class Renderer:
|
||||
def set_text_rectangle(self, rect):
|
||||
""" Sets the rectangle within which text should be rendered"""
|
||||
self._rect=rect
|
||||
|
||||
|
||||
def _render_background(self):
|
||||
# xxx may have to prerender to a memdc when set theme is called for use on slow machines
|
||||
# takes 26ms on mijiti's machine!
|
||||
assert(self._theme)
|
||||
assert(self._paint)
|
||||
print "render background", self._theme.BackgroundType
|
||||
log.debug(u"render background %s %s", self._theme.BackgroundType)
|
||||
p=QtGui.QPainter()
|
||||
p.begin(self._paint)
|
||||
if self._theme.BackgroundType == 0:
|
||||
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter1)
|
||||
elif self._theme.BackgroundType == 1: # gradient
|
||||
# xxx Use a QGradient Brush!!!
|
||||
# get colours as tuples
|
||||
c1=self._theme.BackgroundParameter1.getRgb()
|
||||
c2=self._theme.BackgroundParameter2.getRgb()
|
||||
dir=self._theme.BackgroundParameter3
|
||||
w=self._paint.width();h=self._paint.height()
|
||||
lines=[]
|
||||
pens=[]
|
||||
if dir == 0: # vertical
|
||||
for y in range (h):
|
||||
c=interpolate(c1, c2, y/float(h))
|
||||
lines.append((0,y,w,y))
|
||||
pens.append(QtGui.QPen(QtGui.QColor(c[0],c[1],c[2]))) # bleagh
|
||||
else:
|
||||
for x in range (w):
|
||||
c=interpolate(c1, c2, x/float(w))
|
||||
lines.append((x,0,x,h))
|
||||
pens.append(QtGui.QPen(QtGui.QColor(c[0],c[1],c[2]))) # bleagh
|
||||
for i in range(len(pens)):
|
||||
p.setPen(pens[i])
|
||||
l=lines[i]
|
||||
p.drawLine(l[0],l[1],l[2],l[3]) # must be a better way!
|
||||
#TODO Add Theme code and fix direction
|
||||
|
||||
gradient = QtGui.QLinearGradient(0, 0, self._paint.width(), self._paint.height())
|
||||
gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
|
||||
gradient.setColorAt(0.5, QtGui.QColor(0, 255, 0))
|
||||
gradient.setColorAt(1, QtGui.QColor(0, 0, 255))
|
||||
p.setBrush(QtGui.QBrush(gradient))
|
||||
rectPath = QtGui.QPainterPath()
|
||||
|
||||
MAX_X = self._paint.width()
|
||||
MAX_Y = self._paint.height()
|
||||
|
||||
rectPath.moveTo(0, 0)
|
||||
rectPath.lineTo(0, MAX_Y)
|
||||
rectPath.lineTo(MAX_X, MAX_Y)
|
||||
rectPath.lineTo(MAX_X, 0)
|
||||
rectPath.closeSubpath()
|
||||
p.drawPath(rectPath)
|
||||
|
||||
elif self._theme.BackgroundType == 2: # image
|
||||
r=self._paint.rect()
|
||||
print r.x(), r.y(), r.width(),r.height()
|
||||
print self._theme.BackgroundParameter2
|
||||
log.debug(r.x(), r.y(), r.width(),r.height())
|
||||
log.debug(self._theme.BackgroundParameter2)
|
||||
if self._theme.BackgroundParameter2 is not None:
|
||||
p.fillRect(self._paint.rect(), self._theme.BackgroundParameter2)
|
||||
p.drawPixmap(self.background_offsetx,self.background_offsety, self.img)
|
||||
p.end()
|
||||
print "render background done"
|
||||
|
||||
log.debug(u"render background done")
|
||||
|
||||
def split_set_of_lines(self, lines):
|
||||
|
||||
"""Given a list of lines, decide how to split them best if they don't all fit on the screen
|
||||
@ -166,7 +166,7 @@ class Renderer:
|
||||
|
||||
Returns a list of [lists of lines], one set for each screenful
|
||||
"""
|
||||
# print "Split set of lines"
|
||||
# log.debug(u" "Split set of lines"
|
||||
# Probably ought to save the rendering results to a pseudoDC for redrawing efficiency. But let's not optimse prematurely!
|
||||
|
||||
bboxes = []
|
||||
@ -202,7 +202,7 @@ class Renderer:
|
||||
retval.append(thislines)
|
||||
thislines=[]
|
||||
else:
|
||||
# print "Just split where you can"
|
||||
# log.debug(u" "Just split where you can"
|
||||
retval=[]
|
||||
startline=0
|
||||
endline=startline+1
|
||||
@ -221,9 +221,10 @@ class Renderer:
|
||||
|
||||
def _render_lines(self, lines):
|
||||
"""render a set of lines according to the theme, return bounding box"""
|
||||
print "_render_lines", lines
|
||||
log.debug(u"_render_lines %s", lines)
|
||||
|
||||
bbox=self._render_lines_unaligned(lines)
|
||||
print bbox
|
||||
|
||||
t=self._theme
|
||||
x=self._rect.left()
|
||||
@ -237,10 +238,10 @@ class Renderer:
|
||||
assert(0, "Invalid value for theme.VerticalAlign:%d" % t.VerticalAlign)
|
||||
self._render_background()
|
||||
bbox=self._render_lines_unaligned(lines, (x,y))
|
||||
print "render lines DONE"
|
||||
log.debug(u"render lines DONE")
|
||||
|
||||
return bbox
|
||||
|
||||
|
||||
def _render_lines_unaligned(self, lines, tlcorner=(0,0)):
|
||||
|
||||
"""Given a list of lines to render, render each one in turn
|
||||
@ -249,7 +250,7 @@ class Renderer:
|
||||
than a screenful (eg. by using split_set_of_lines)
|
||||
|
||||
Returns the bounding box of the text as QRect"""
|
||||
print "render unaligned", lines
|
||||
log.debug(u"render unaligned %s", lines)
|
||||
x,y=tlcorner
|
||||
brx=x
|
||||
bry=y
|
||||
@ -268,7 +269,7 @@ class Renderer:
|
||||
p.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
|
||||
p.drawRect(retval)
|
||||
p.end()
|
||||
print "render unaligned DONE"
|
||||
log.debug(u"render unaligned DONE")
|
||||
|
||||
return retval
|
||||
|
||||
@ -282,14 +283,14 @@ class Renderer:
|
||||
|
||||
Returns the bottom-right corner (of what was rendered) as a tuple(x,y).
|
||||
"""
|
||||
print "Render single line '%s' @ %s "%( line, tlcorner)
|
||||
log.debug(u"Render single line '%s' @ %s "%( line, tlcorner))
|
||||
x,y=tlcorner
|
||||
# We draw the text to see how big it is and then iterate to make it fit
|
||||
# when we line wrap we do in in the "lyrics" style, so the second line is
|
||||
# right aligned with a "hanging indent"
|
||||
|
||||
# get the words
|
||||
# print "Getting the words split right"
|
||||
# log.debug(u" "Getting the words split right"
|
||||
words=line.split(" ")
|
||||
thisline=' '.join(words)
|
||||
lastword=len(words)
|
||||
@ -307,8 +308,8 @@ class Renderer:
|
||||
lastword-=1
|
||||
thisline=' '.join(words[:lastword])
|
||||
|
||||
# print "This is how they split", lines
|
||||
# print "Now render them"
|
||||
# log.debug(u" "This is how they split", lines
|
||||
# log.debug(u" "Now render them"
|
||||
startx=x
|
||||
starty=y
|
||||
rightextent=None
|
||||
@ -356,7 +357,7 @@ class Renderer:
|
||||
self._get_extent_and_render(line, (x-self._outline_offset,y-self._outline_offset), dodraw=True, color = t.OutlineColor)
|
||||
|
||||
self._get_extent_and_render(line, tlcorner=(x,y), dodraw=True)
|
||||
# print "Line %2d: Render '%s' at (%d, %d) wh=(%d,%d)"%( linenum, line, x, y,w,h)
|
||||
# log.debug(u" "Line %2d: Render '%s' at (%d, %d) wh=(%d,%d)"%( linenum, line, x, y,w,h)
|
||||
y += h
|
||||
if linenum == 0:
|
||||
self._first_line_right_extent=rightextent
|
||||
@ -372,28 +373,36 @@ class Renderer:
|
||||
return brcorner
|
||||
|
||||
# xxx this is what to override for an SDL version
|
||||
def _get_extent_and_render(self, line, tlcorner=(0,0), dodraw=False, color=None):
|
||||
def _get_extent_and_render(self, line, tlcorner=(0,0), dodraw=False, color=None, footer = False):
|
||||
"""Find bounding box of text - as render_single_line.
|
||||
If dodraw is set, actually draw the text to the current DC as well
|
||||
|
||||
return width and height of text as a tuple (w,h)"""
|
||||
# setup defaults
|
||||
print "_get_extent_and_render", [line], tlcorner, dodraw
|
||||
log.debug(u"_get_extent_and_render %s %s %s ", [line], tlcorner, dodraw)
|
||||
p=QtGui.QPainter()
|
||||
p.begin(self._paint)
|
||||
# 'twould be more efficient to set this once when theme changes
|
||||
# or p changes
|
||||
font=QtGui.QFont(self._theme.FontName,
|
||||
self._theme.FontProportion, # size
|
||||
QtGui.QFont.Normal, # weight
|
||||
0)# italic
|
||||
if footer :
|
||||
font=QtGui.QFont(self._theme.FontName,
|
||||
12, # size
|
||||
QtGui.QFont.Normal, # weight
|
||||
0)# italic
|
||||
else:
|
||||
font=QtGui.QFont(self._theme.FontName,
|
||||
self._theme.FontProportion, # size
|
||||
QtGui.QFont.Normal, # weight
|
||||
0)# italic
|
||||
# to make the unit tests monitor independent, we have to be able to
|
||||
# specify whether a font proportion is in pixels or points
|
||||
if self._theme.FontUnits.lower() == "pixels":
|
||||
print "pixels"
|
||||
font.setPixelSize(self._theme.FontProportion)
|
||||
print self._theme.FontName, self._theme.FontProportion
|
||||
print font.family(), font.pointSize()
|
||||
log.debug(u"pixels")
|
||||
if footer:
|
||||
font.setPixelSize(12)
|
||||
else:
|
||||
font.setPixelSize(self._theme.FontProportion)
|
||||
log.debug(u'Font details %s %s %s %s', self._theme.FontName, self._theme.FontProportion, font.family(), font.pointSize())
|
||||
p.setFont(font)
|
||||
if color == None:
|
||||
p.setPen(self._theme.FontColor)
|
||||
|
@ -81,6 +81,7 @@ class TestRender_base:
|
||||
def teardown_class(self):
|
||||
print "class quit", self, self.app
|
||||
self.app.quit()
|
||||
|
||||
def setup_method(self, method):
|
||||
print "SSsetup", method
|
||||
if not hasattr(self, "app"):
|
||||
@ -157,6 +158,7 @@ Line 3"""
|
||||
expected_answer=["Verse 1: Line 1\nLine 2","Verse 2: Line 1\nLine 2","Verse 3: Line 1\nLine 2\nLine 3"]
|
||||
answer=self.r.set_words_openlp(words)
|
||||
assert (answer==expected_answer)
|
||||
|
||||
def test_render_screens(self):
|
||||
words="""
|
||||
Verse 1: Line 1
|
||||
@ -177,6 +179,7 @@ Line 3"""
|
||||
answer=self.r.render_screen(v)
|
||||
# print v, answer.x(), answer.y(), answer.width(), answer.height()
|
||||
assert(answer==expected_answer[v])
|
||||
|
||||
def split_test(self, number, answer, expected_answers):
|
||||
lines=[]
|
||||
print "Split test", number, answer
|
||||
|
@ -8,6 +8,8 @@ else:
|
||||
from PyQt4 import QtGui
|
||||
|
||||
DelphiColors={"clRed":0xFF0000,
|
||||
"clBlue":0x0000FF,
|
||||
"clYellow":0x0FFFF00,
|
||||
"clBlack":0x000000,
|
||||
"clWhite":0xFFFFFF}
|
||||
|
||||
@ -16,7 +18,7 @@ blankstylexml=\
|
||||
<Theme>
|
||||
<Name>BlankStyle</Name>
|
||||
<BackgroundMode>1</BackgroundMode>
|
||||
<BackgroundType>0</BackgroundType>
|
||||
<BackgroundType>0</BackgroundType>
|
||||
<BackgroundParameter1>$000000</BackgroundParameter1>
|
||||
<BackgroundParameter2/>
|
||||
<BackgroundParameter3/>
|
||||
@ -37,10 +39,10 @@ class Theme:
|
||||
""" stores the info about a theme
|
||||
attributes:
|
||||
name : theme name
|
||||
|
||||
|
||||
BackgroundMode : 1 - Transparent
|
||||
1 - Opaque
|
||||
|
||||
|
||||
BackgroundType : 0 - solid color
|
||||
1 - gradient color
|
||||
2 - image
|
||||
@ -53,7 +55,7 @@ class Theme:
|
||||
for solid - N/A
|
||||
BackgroundParameter3 : for image - N/A
|
||||
for gradient - 0 -> vertical, 1 -> horizontal
|
||||
|
||||
|
||||
FontName : name of font to use
|
||||
FontColor : color for main font
|
||||
FontProportion : size of font
|
||||
@ -108,7 +110,7 @@ class Theme:
|
||||
# print "nope",
|
||||
pass
|
||||
elif DelphiColors.has_key(t):
|
||||
# print "colour",
|
||||
# print "colour",
|
||||
val=DelphiColors[t]
|
||||
else:
|
||||
try:
|
||||
@ -121,7 +123,7 @@ class Theme:
|
||||
val= QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
|
||||
# print [val]
|
||||
setattr(self,element.tag, val)
|
||||
|
||||
|
||||
|
||||
def __str__(self):
|
||||
s=""
|
||||
|
@ -17,17 +17,22 @@ You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
import os
|
||||
import os,os.path
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
from time import sleep
|
||||
from copy import deepcopy
|
||||
from xml.etree.ElementTree import ElementTree, XML
|
||||
from PyQt4 import *
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4.QtCore import *
|
||||
from PyQt4.QtGui import *
|
||||
# from openlp.core.resources import *
|
||||
# from openlp.core.ui import AboutForm, AlertForm, SettingsForm, SlideController
|
||||
from openlp.core import translate
|
||||
from openlp.core.lib import OpenLPToolbar
|
||||
from openlp.core.utils import ConfigHelper
|
||||
#from openlp.core.lib import ThemeItem
|
||||
|
||||
# from openlp.core import PluginManager
|
||||
@ -44,53 +49,74 @@ class ThemeData(QAbstractItemModel):
|
||||
def __init__(self):
|
||||
QAbstractItemModel.__init__(self)
|
||||
self.items=[]
|
||||
self.rowheight=50
|
||||
self.maximagewidth=self.rowheight*16/9.0;
|
||||
log.info("Starting")
|
||||
|
||||
def clearItems(self):
|
||||
self.items=[]
|
||||
|
||||
def columnCount(self, parent):
|
||||
return 1; # always only a single column (for now)
|
||||
|
||||
def rowCount(self, parent):
|
||||
return len(self.items)
|
||||
def insertRow(self, row, Theme_item):
|
||||
# self.beginInsertRows(QModelIndex(),row,row)
|
||||
log.info("insert row %d:%s"%(row,Theme_item))
|
||||
self.items.insert(row, Theme_item)
|
||||
|
||||
def insertRow(self, row, filename):
|
||||
self.beginInsertRows(QModelIndex(),row,row)
|
||||
log.info("insert row %d:%s"%(row,filename))
|
||||
(prefix, shortfilename) = os.path.split(str(filename))
|
||||
log.info("shortfilename=%s"%(shortfilename))
|
||||
# create a preview image
|
||||
if os.path.exists(filename):
|
||||
preview = QPixmap(str(filename))
|
||||
w=self.maximagewidth;h=self.rowheight
|
||||
preview = preview.scaled(w,h, Qt.KeepAspectRatio)
|
||||
realw=preview.width(); realh=preview.height()
|
||||
# and move it to the centre of the preview space
|
||||
p=QPixmap(w,h)
|
||||
p.fill(Qt.transparent)
|
||||
painter=QPainter(p)
|
||||
painter.drawPixmap((w-realw)/2,(h-realh)/2,preview)
|
||||
else:
|
||||
w=self.maximagewidth;h=self.rowheight
|
||||
p=QPixmap(w,h)
|
||||
p.fill(Qt.transparent)
|
||||
# finally create the row
|
||||
self.items.insert(row,(filename, p, shortfilename))
|
||||
log.info("Items: %s" % self.items)
|
||||
# self.endInsertRows()
|
||||
self.endInsertRows()
|
||||
|
||||
def removeRow(self, row):
|
||||
self.beginRemoveRows(QModelIndex(), row,row)
|
||||
self.items.pop(row)
|
||||
self.endRemoveRows()
|
||||
|
||||
def addRow(self, item):
|
||||
self.insertRow(len(self.items), item)
|
||||
|
||||
|
||||
def index(self, row, col, parent = QModelIndex()):
|
||||
return self.createIndex(row,col)
|
||||
|
||||
def parent(self, index=QModelIndex()):
|
||||
return QModelIndex() # no children as yet
|
||||
|
||||
def data(self, index, role):
|
||||
"""
|
||||
Called by the Theme manager to draw us in the Theme window
|
||||
"""
|
||||
row=index.row()
|
||||
if row > len(self.items): # if the last row is selected and deleted, we then get called with an empty row!
|
||||
return QVariant()
|
||||
item=self.items[row]
|
||||
if role==Qt.DisplayRole:
|
||||
retval= item.pluginname + ":" + item.shortname
|
||||
retval= self.items[row][2]
|
||||
elif role == Qt.DecorationRole:
|
||||
retval = item.iconic_representation
|
||||
elif role == Qt.ToolTipRole:
|
||||
retval= None
|
||||
retval= self.items[row][1]
|
||||
else:
|
||||
retval= None
|
||||
if retval == None:
|
||||
retval=QVariant()
|
||||
retval= QVariant()
|
||||
# log.info("Returning"+ str(retval))
|
||||
if type(retval) is not type(QVariant):
|
||||
return QVariant(retval)
|
||||
else:
|
||||
return retval
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
for i in self.items:
|
||||
yield i
|
||||
@ -99,14 +125,9 @@ class ThemeData(QAbstractItemModel):
|
||||
log.info("Get Item:%d -> %s" %(row, str(self.items)))
|
||||
return self.items[row]
|
||||
|
||||
|
||||
class ThemeManager(QWidget):
|
||||
|
||||
"""Manages the orders of Theme. Currently this involves taking
|
||||
text strings from plugins and adding them to an OOS file. In
|
||||
future, it will also handle zipping up all the resources used into
|
||||
one lump.
|
||||
Also handles the UI tasks of moving things up and down etc.
|
||||
"""
|
||||
Manages the orders of Theme. C
|
||||
"""
|
||||
global log
|
||||
log=logging.getLogger(u'ThemeManager')
|
||||
@ -122,19 +143,26 @@ class ThemeManager(QWidget):
|
||||
self.Toolbar.addToolbarButton("Edit Theme", ":/themes/theme_edit.png")
|
||||
self.Toolbar.addToolbarButton("Delete Theme", ":/themes/theme_delete.png")
|
||||
self.Toolbar.addSeparator()
|
||||
self.Toolbar.addToolbarButton("Import Theme", ":/themes/theme_import.png")
|
||||
self.Toolbar.addToolbarButton("Export Theme", ":/themes/theme_export.png")
|
||||
self.Toolbar.addToolbarButton("Import Theme", ":/themes/theme_import.png",
|
||||
u'Allows Themes to be imported', self.onImportTheme)
|
||||
self.Toolbar.addToolbarButton("Export Theme", ":/themes/theme_export.png")
|
||||
self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
|
||||
self.Toolbar.addAction(self.ThemeWidget)
|
||||
|
||||
self.Layout.addWidget(self.Toolbar)
|
||||
|
||||
self.TreeView = QtGui.QTreeView(self)
|
||||
self.ThemeListView = QtGui.QListView(self)
|
||||
self.Theme_data=ThemeData()
|
||||
self.TreeView.setModel(self.Theme_data)
|
||||
self.Layout.addWidget(self.TreeView)
|
||||
self.ThemeListView.setModel(self.Theme_data)
|
||||
self.ThemeListView.setAlternatingRowColors(True)
|
||||
self.Layout.addWidget(self.ThemeListView)
|
||||
self.ThemeListView.setAlternatingRowColors(True)
|
||||
|
||||
self.themelist= []
|
||||
|
||||
self.path = os.path.join(ConfigHelper.get_data_path(), u'themes')
|
||||
self.checkThemesExists(self.path)
|
||||
self.loadThemes() # load the themes
|
||||
|
||||
# def addThemeItem(self, item):
|
||||
# """Adds Theme item"""
|
||||
# log.info("addThemeItem")
|
||||
@ -158,7 +186,7 @@ class ThemeManager(QWidget):
|
||||
# self.Theme_data.addRow(item)
|
||||
# else:
|
||||
# self.Theme_data.insertRow(row+1, item)
|
||||
#
|
||||
#
|
||||
# def removeThemeItem(self):
|
||||
# """Remove currently selected item"""
|
||||
# pass
|
||||
@ -182,10 +210,55 @@ class ThemeManager(QWidget):
|
||||
# oosfile.write(self.oos_as_text)
|
||||
# oosfile.write("# END OOS\n")
|
||||
# oosfile.close()
|
||||
|
||||
def load(self):
|
||||
log.debug(u'Load')
|
||||
self.themelist = [u'African Sunset', u'Snowy Mountains', u'Wilderness', u'Wet and Windy London']
|
||||
|
||||
|
||||
def onImportTheme(self):
|
||||
files = QtGui.QFileDialog.getOpenFileNames(None,
|
||||
translate('ThemeManager', u'Select Import File'),
|
||||
self.path,
|
||||
u'Theme (*.theme)')
|
||||
log.info(u'New Themes) %s', str(files))
|
||||
if len(files) > 0:
|
||||
for file in files:
|
||||
self.unzipTheme(file, self.path)
|
||||
self.Theme_data.clearItems()
|
||||
self.loadThemes()
|
||||
|
||||
def loadThemes(self):
|
||||
log.debug(u'Load themes from dir')
|
||||
# self.themelist = [u'African Sunset', u'Snowy Mountains', u'Wilderness', u'Wet and Windy London']
|
||||
for root, dirs, files in os.walk(self.path):
|
||||
for name in files:
|
||||
if name.endswith(u'.bmp'):
|
||||
self.Theme_data.addRow(os.path.join(self.path, name))
|
||||
|
||||
def getThemes(self):
|
||||
return self.themelist
|
||||
|
||||
def checkThemesExists(self, dir):
|
||||
log.debug(u'check themes')
|
||||
if os.path.exists(dir) == False:
|
||||
os.mkdir(dir)
|
||||
|
||||
def unzipTheme(self, filename, dir):
|
||||
log.debug(u'Unzipping theme %s', filename)
|
||||
zip = zipfile.ZipFile(str(filename))
|
||||
for file in zip.namelist():
|
||||
if file.endswith('/'):
|
||||
theme_dir = os.path.join(dir, file)
|
||||
if os.path.exists(theme_dir) == False:
|
||||
os.mkdir(os.path.join(dir, file))
|
||||
else:
|
||||
fullpath = os.path.join(dir, file)
|
||||
if file.endswith(u'.xml'):
|
||||
self.checkVersion1(fullpath)
|
||||
outfile = open(fullpath, 'w')
|
||||
outfile.write(zip.read(file))
|
||||
outfile.close()
|
||||
|
||||
def checkVersion1(self, xmlfile):
|
||||
file=open(xmlfile)
|
||||
t=''.join(file.readlines()) # read the file and change list to a string
|
||||
tree = ElementTree(element=XML(t)).getroot()
|
||||
print "AA"
|
||||
print tree.find('BackgroundType')
|
||||
print "AAA"
|
||||
|
Loading…
Reference in New Issue
Block a user