Merge lp:~meths/openlp/testing into lp:openlp

Proposed by Jon Tibble
Status: Merged
Merged at revision: not available
Proposed branch: lp:~meths/openlp/testing
Merge into: lp:openlp
Diff against target: None lines
To merge this branch: bzr merge lp:~meths/openlp/testing
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Raoul Snyman Approve
Review via email: mp+11667@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jon Tibble (meths) wrote :

dos2unix

Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve
Revision history for this message
Tim Bentley (trb143) wrote :

Approved

review: Approve
lp:~meths/openlp/testing updated
536. By Jon Tibble

For Jon

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'demo_theme.xml'
2--- demo_theme.xml 2008-10-07 19:12:32 +0000
3+++ demo_theme.xml 2009-09-13 15:14:45 +0000
4@@ -1,17 +1,17 @@
5-<?xml version="1.0" encoding="iso-8859-1"?>
6-<Theme>
7- <Name>openlp.org 2.0 Demo Theme</Name>
8- <BackgroundType>2</BackgroundType>
9- <BackgroundParameter1>./openlp/core/test/data_for_tests/treesbig.jpg</BackgroundParameter1>
10- <BackgroundParameter2>clBlack</BackgroundParameter2>
11- <BackgroundParameter3/>
12- <FontName>Tahoma</FontName>
13- <FontColor>clWhite</FontColor>
14- <FontProportion>16</FontProportion>
15- <Shadow>-1</Shadow>
16- <ShadowColor>$00000001</ShadowColor>
17- <Outline>-1</Outline>
18- <OutlineColor>clRed</OutlineColor>
19- <HorizontalAlign>2</HorizontalAlign>
20- <VerticalAlign>2</VerticalAlign>
21-</Theme>
22+<?xml version="1.0" encoding="iso-8859-1"?>
23+<Theme>
24+ <Name>openlp.org 2.0 Demo Theme</Name>
25+ <BackgroundType>2</BackgroundType>
26+ <BackgroundParameter1>./openlp/core/test/data_for_tests/treesbig.jpg</BackgroundParameter1>
27+ <BackgroundParameter2>clBlack</BackgroundParameter2>
28+ <BackgroundParameter3/>
29+ <FontName>Tahoma</FontName>
30+ <FontColor>clWhite</FontColor>
31+ <FontProportion>16</FontProportion>
32+ <Shadow>-1</Shadow>
33+ <ShadowColor>$00000001</ShadowColor>
34+ <Outline>-1</Outline>
35+ <OutlineColor>clRed</OutlineColor>
36+ <HorizontalAlign>2</HorizontalAlign>
37+ <VerticalAlign>2</VerticalAlign>
38+</Theme>
39
40=== modified file 'documentation/pyqt-sql-py2exe.txt'
41--- documentation/pyqt-sql-py2exe.txt 2008-11-27 20:14:38 +0000
42+++ documentation/pyqt-sql-py2exe.txt 2009-09-13 15:14:45 +0000
43@@ -1,58 +1,58 @@
44-This content can be found at this URL:
45-http://netsuperbrain.com/Postmodern%20PostgreSQL%20Application%20Development.pdf
46-
47-Page 11-15: QtDesigner
48-Page 18-20: SQLAlchemy
49-Page 21-23: PyQt - widget
50-Page 24 : main
51-Page 28 : py2exe and release
52-
53-
54-==============================
55-This is the destilled content.
56-==============================
57-
58-----------------
59-** sqlalchemy **
60-----------------
61-from sqlalchemy import create_engine, MetaData, Table
62-from sqlalchemy.orm import sessionmaker, mapper
63-engine = create_engine( 'postgres://postgres@localhost/customers' )
64-metadata = MetaData( bind=engine, reflect=True)
65-Session = sessionmaker(bind=engine, autoflush=True,
66- transactional=True)
67-
68-class Customer(object): pass
69-mapper( Customer, Table('customers', metadata ) )
70-
71-session = Session()
72-customer = Customer( businessName=“Jamb Safety”,
73- website=“www.jamb.com” )
74-session.save( customer )
75-for customer in Session.query(Customer).filter(
76- Customer.businessName.like(“Jamb%”)):
77- print customer.businessName
78-session.commit()
79-
80-------------------------
81-** release and py2exe **
82-------------------------
83-
84-from distutils.core import setup
85-import py2exe
86-import glob
87-setup(
88- name="Customers",
89- author="Sankel Software",
90- author_email="david@sankelsoftware.com",
91- url="http://sankelsoftware.com",
92- license=“GPL",
93- version=“1.0.0",
94- windows=[ { "script":"main.py“,}],
95- options={"py2exe":{"includes":["sip”]}},
96- data_files=[
97- ("forms",glob.glob("forms/*.ui")),
98- ] )
99-
100-release:
101-python setup.py py2exe --quiet --dist-dir=dist
102+This content can be found at this URL:
103+http://netsuperbrain.com/Postmodern%20PostgreSQL%20Application%20Development.pdf
104+
105+Page 11-15: QtDesigner
106+Page 18-20: SQLAlchemy
107+Page 21-23: PyQt - widget
108+Page 24 : main
109+Page 28 : py2exe and release
110+
111+
112+==============================
113+This is the destilled content.
114+==============================
115+
116+----------------
117+** sqlalchemy **
118+----------------
119+from sqlalchemy import create_engine, MetaData, Table
120+from sqlalchemy.orm import sessionmaker, mapper
121+engine = create_engine( 'postgres://postgres@localhost/customers' )
122+metadata = MetaData( bind=engine, reflect=True)
123+Session = sessionmaker(bind=engine, autoflush=True,
124+ transactional=True)
125+
126+class Customer(object): pass
127+mapper( Customer, Table('customers', metadata ) )
128+
129+session = Session()
130+customer = Customer( businessName=“Jamb Safety”,
131+ website=“www.jamb.com” )
132+session.save( customer )
133+for customer in Session.query(Customer).filter(
134+ Customer.businessName.like(“Jamb%”)):
135+ print customer.businessName
136+session.commit()
137+
138+------------------------
139+** release and py2exe **
140+------------------------
141+
142+from distutils.core import setup
143+import py2exe
144+import glob
145+setup(
146+ name="Customers",
147+ author="Sankel Software",
148+ author_email="david@sankelsoftware.com",
149+ url="http://sankelsoftware.com",
150+ license=“GPL",
151+ version=“1.0.0",
152+ windows=[ { "script":"main.py“,}],
153+ options={"py2exe":{"includes":["sip”]}},
154+ data_files=[
155+ ("forms",glob.glob("forms/*.ui")),
156+ ] )
157+
158+release:
159+python setup.py py2exe --quiet --dist-dir=dist
160
161=== modified file 'openlp/core/test/data_for_tests/render_theme.xml'
162--- openlp/core/test/data_for_tests/render_theme.xml 2009-03-12 20:19:24 +0000
163+++ openlp/core/test/data_for_tests/render_theme.xml 2009-09-13 15:14:45 +0000
164@@ -1,19 +1,19 @@
165-<?xml version="1.0" encoding="iso-8859-1"?>
166-<Theme>
167- <Name>openlp.org Packaged Theme</Name>
168- <BackgroundType>0</BackgroundType>
169- <BackgroundParameter1>clWhite</BackgroundParameter1>
170- <BackgroundParameter2/>
171- <BackgroundParameter3/>
172- <FontName>Tahoma</FontName>
173- <FontColor>$00007F</FontColor>
174- <FontProportion>53</FontProportion>
175- <FontUnits>pixels</FontUnits>
176- <Shadow>0</Shadow>
177- <ShadowColor>$000000</ShadowColor>
178- <Outline>0</Outline>
179- <OutlineColor>$000000</OutlineColor>
180- <HorizontalAlign>0</HorizontalAlign>
181- <VerticalAlign>0</VerticalAlign>
182- <WrapStyle>1</WrapStyle>
183-</Theme>
184+<?xml version="1.0" encoding="iso-8859-1"?>
185+<Theme>
186+ <Name>openlp.org Packaged Theme</Name>
187+ <BackgroundType>0</BackgroundType>
188+ <BackgroundParameter1>clWhite</BackgroundParameter1>
189+ <BackgroundParameter2/>
190+ <BackgroundParameter3/>
191+ <FontName>Tahoma</FontName>
192+ <FontColor>$00007F</FontColor>
193+ <FontProportion>53</FontProportion>
194+ <FontUnits>pixels</FontUnits>
195+ <Shadow>0</Shadow>
196+ <ShadowColor>$000000</ShadowColor>
197+ <Outline>0</Outline>
198+ <OutlineColor>$000000</OutlineColor>
199+ <HorizontalAlign>0</HorizontalAlign>
200+ <VerticalAlign>0</VerticalAlign>
201+ <WrapStyle>1</WrapStyle>
202+</Theme>
203
204=== modified file 'openlp/core/theme/test/test_theme.xml'
205--- openlp/core/theme/test/test_theme.xml 2009-03-12 20:19:24 +0000
206+++ openlp/core/theme/test/test_theme.xml 2009-09-13 15:14:45 +0000
207@@ -1,18 +1,18 @@
208-<?xml version="1.0" encoding="iso-8859-1"?>
209-<Theme>
210- <Name>openlp.org Packaged Theme</Name>
211- <BackgroundType>2</BackgroundType>
212- <BackgroundParameter1>sunset1.jpg</BackgroundParameter1>
213- <BackgroundParameter2/>
214- <BackgroundParameter3/>
215- <FontName>Tahoma</FontName>
216- <FontColor>clWhite</FontColor>
217- <FontProportion>16</FontProportion>
218- <FontUnits>pixels</FontUnits>
219- <Shadow>-1</Shadow>
220- <ShadowColor>$00000001</ShadowColor>
221- <Outline>-1</Outline>
222- <OutlineColor>clRed</OutlineColor>
223- <HorizontalAlign>2</HorizontalAlign>
224- <VerticalAlign>0</VerticalAlign>
225-</Theme>
226+<?xml version="1.0" encoding="iso-8859-1"?>
227+<Theme>
228+ <Name>openlp.org Packaged Theme</Name>
229+ <BackgroundType>2</BackgroundType>
230+ <BackgroundParameter1>sunset1.jpg</BackgroundParameter1>
231+ <BackgroundParameter2/>
232+ <BackgroundParameter3/>
233+ <FontName>Tahoma</FontName>
234+ <FontColor>clWhite</FontColor>
235+ <FontProportion>16</FontProportion>
236+ <FontUnits>pixels</FontUnits>
237+ <Shadow>-1</Shadow>
238+ <ShadowColor>$00000001</ShadowColor>
239+ <Outline>-1</Outline>
240+ <OutlineColor>clRed</OutlineColor>
241+ <HorizontalAlign>2</HorizontalAlign>
242+ <VerticalAlign>0</VerticalAlign>
243+</Theme>
244
245=== modified file 'openlp/core/ui/amendthemeform.py'
246--- openlp/core/ui/amendthemeform.py 2009-09-13 14:12:38 +0000
247+++ openlp/core/ui/amendthemeform.py 2009-09-13 15:14:45 +0000
248@@ -1,716 +1,716 @@
249-# -*- coding: utf-8 -*-
250-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
251-
252-###############################################################################
253-# OpenLP - Open Source Lyrics Projection #
254-# --------------------------------------------------------------------------- #
255-# Copyright (c) 2008-2009 Raoul Snyman #
256-# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
257-# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
258-# --------------------------------------------------------------------------- #
259-# This program is free software; you can redistribute it and/or modify it #
260-# under the terms of the GNU General Public License as published by the Free #
261-# Software Foundation; version 2 of the License. #
262-# #
263-# This program is distributed in the hope that it will be useful, but WITHOUT #
264-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
265-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
266-# more details. #
267-# #
268-# You should have received a copy of the GNU General Public License along #
269-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
270-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
271-###############################################################################
272-
273-import logging
274-import os, os.path
275-
276-from PyQt4 import QtCore, QtGui
277-from openlp.core.lib import ThemeXML, Renderer, file_to_xml, str_to_bool, \
278- translate
279-
280-from amendthemedialog import Ui_AmendThemeDialog
281-
282-log = logging.getLogger(u'AmendThemeForm')
283-
284-class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
285-
286- def __init__(self, thememanager, parent=None):
287- QtGui.QDialog.__init__(self, parent)
288- self.thememanager = thememanager
289- self.path = None
290- self.theme = ThemeXML()
291- self.setupUi(self)
292- #define signals
293- #Buttons
294- QtCore.QObject.connect(self.Color1PushButton ,
295- QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
296- QtCore.QObject.connect(self.Color2PushButton ,
297- QtCore.SIGNAL(u'pressed()'), self.onColor2PushButtonClicked)
298- QtCore.QObject.connect(self.FontMainColorPushButton,
299- QtCore.SIGNAL(u'pressed()'), self.onFontMainColorPushButtonClicked)
300- QtCore.QObject.connect(self.FontFooterColorPushButton,
301- QtCore.SIGNAL(u'pressed()'),
302- self.onFontFooterColorPushButtonClicked)
303- QtCore.QObject.connect(self.OutlineColorPushButton,
304- QtCore.SIGNAL(u'pressed()'), self.onOutlineColorPushButtonClicked)
305- QtCore.QObject.connect(self.ShadowColorPushButton,
306- QtCore.SIGNAL(u'pressed()'), self.onShadowColorPushButtonClicked)
307- QtCore.QObject.connect(self.ImageToolButton,
308- QtCore.SIGNAL(u'pressed()'), self.onImageToolButtonClicked)
309- #Combo boxes
310- QtCore.QObject.connect(self.BackgroundComboBox,
311- QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected)
312- QtCore.QObject.connect(self.BackgroundTypeComboBox,
313- QtCore.SIGNAL(u'activated(int)'),
314- self.onBackgroundTypeComboBoxSelected)
315- QtCore.QObject.connect(self.GradientComboBox,
316- QtCore.SIGNAL(u'activated(int)'), self.onGradientComboBoxSelected)
317- QtCore.QObject.connect(self.FontMainComboBox,
318- QtCore.SIGNAL(u'activated(int)'), self.onFontMainComboBoxSelected)
319- QtCore.QObject.connect(self.FontMainWeightComboBox,
320- QtCore.SIGNAL(u'activated(int)'),
321- self.onFontMainWeightComboBoxSelected)
322- QtCore.QObject.connect(self.FontFooterComboBox,
323- QtCore.SIGNAL(u'activated(int)'), self.onFontFooterComboBoxSelected)
324- QtCore.QObject.connect(self.FontFooterWeightComboBox,
325- QtCore.SIGNAL(u'activated(int)'),
326- self.onFontFooterWeightComboBoxSelected)
327- QtCore.QObject.connect(self.HorizontalComboBox,
328- QtCore.SIGNAL(u'activated(int)'), self.onHorizontalComboBoxSelected)
329- QtCore.QObject.connect(self.VerticalComboBox,
330- QtCore.SIGNAL(u'activated(int)'), self.onVerticalComboBoxSelected)
331- #Spin boxes
332- QtCore.QObject.connect(self.FontMainSizeSpinBox,
333- QtCore.SIGNAL(u'editingFinished()'),
334- self.onFontMainSizeSpinBoxChanged)
335- QtCore.QObject.connect(self.FontFooterSizeSpinBox,
336- QtCore.SIGNAL(u'editingFinished()'),
337- self.onFontFooterSizeSpinBoxChanged)
338- QtCore.QObject.connect(self.FontMainDefaultCheckBox,
339- QtCore.SIGNAL(u'stateChanged(int)'),
340- self.onFontMainDefaultCheckBoxChanged)
341- QtCore.QObject.connect(self.FontMainXSpinBox,
342- QtCore.SIGNAL(u'editingFinished()'), self.onFontMainXSpinBoxChanged)
343- QtCore.QObject.connect(self.FontMainYSpinBox,
344- QtCore.SIGNAL(u'editingFinished()'), self.onFontMainYSpinBoxChanged)
345- QtCore.QObject.connect(self.FontMainWidthSpinBox,
346- QtCore.SIGNAL(u'editingFinished()'),
347- self.onFontMainWidthSpinBoxChanged)
348- QtCore.QObject.connect(self.FontMainHeightSpinBox,
349- QtCore.SIGNAL(u'editingFinished()'),
350- self.onFontMainHeightSpinBoxChanged)
351- QtCore.QObject.connect(self.FontFooterDefaultCheckBox,
352- QtCore.SIGNAL(u'stateChanged(int)'),
353- self.onFontFooterDefaultCheckBoxChanged)
354- QtCore.QObject.connect(self.FontFooterXSpinBox,
355- QtCore.SIGNAL(u'editingFinished()'),
356- self.onFontFooterXSpinBoxChanged)
357- QtCore.QObject.connect(self.FontFooterYSpinBox,
358- QtCore.SIGNAL(u'editingFinished()'),
359- self.onFontFooterYSpinBoxChanged)
360- QtCore.QObject.connect(self.FontFooterWidthSpinBox,
361- QtCore.SIGNAL(u'editingFinished()'),
362- self.onFontFooterWidthSpinBoxChanged)
363- QtCore.QObject.connect(self.FontFooterHeightSpinBox,
364- QtCore.SIGNAL(u'editingFinished()'),
365- self.onFontFooterHeightSpinBoxChanged)
366- QtCore.QObject.connect(self.OutlineCheckBox,
367- QtCore.SIGNAL(u'stateChanged(int)'), self.onOutlineCheckBoxChanged)
368- QtCore.QObject.connect(self.ShadowCheckBox,
369- QtCore.SIGNAL(u'stateChanged(int)'), self.onShadowCheckBoxChanged)
370-
371- def accept(self):
372- new_theme = ThemeXML()
373- theme_name = unicode(self.ThemeNameEdit.displayText())
374- new_theme.new_document(theme_name)
375- save_from = None
376- save_to = None
377- if self.theme.background_mode == u'transparent':
378- new_theme.add_background_transparent()
379- else:
380- if self.theme.background_type == u'solid':
381- new_theme.add_background_solid( \
382- unicode(self.theme.background_color))
383- elif self.theme.background_type == u'gradient':
384- new_theme.add_background_gradient( \
385- unicode(self.theme.background_startColor),
386- unicode(self.theme.background_endColor),
387- self.theme.background_direction)
388- else:
389- (path, filename) = \
390- os.path.split(unicode(self.theme.background_filename))
391- new_theme.add_background_image(filename)
392- save_to= os.path.join(self.path, theme_name, filename )
393- save_from = self.theme.background_filename
394-
395- new_theme.add_font(unicode(self.theme.font_main_name),
396- unicode(self.theme.font_main_color),
397- unicode(self.theme.font_main_proportion),
398- unicode(self.theme.font_main_override), u'main',
399- unicode(self.theme.font_main_weight),
400- unicode(self.theme.font_main_italics),
401- unicode(self.theme.font_main_x),
402- unicode(self.theme.font_main_y),
403- unicode(self.theme.font_main_width),
404- unicode(self.theme.font_main_height))
405- new_theme.add_font(unicode(self.theme.font_footer_name),
406- unicode(self.theme.font_footer_color),
407- unicode(self.theme.font_footer_proportion),
408- unicode(self.theme.font_footer_override), u'footer',
409- unicode(self.theme.font_footer_weight),
410- unicode(self.theme.font_footer_italics),
411- unicode(self.theme.font_footer_x),
412- unicode(self.theme.font_footer_y),
413- unicode(self.theme.font_footer_width),
414- unicode(self.theme.font_footer_height) )
415- new_theme.add_display(unicode(self.theme.display_shadow),
416- unicode(self.theme.display_shadow_color),
417- unicode(self.theme.display_outline),
418- unicode(self.theme.display_outline_color),
419- unicode(self.theme.display_horizontalAlign),
420- unicode(self.theme.display_verticalAlign),
421- unicode(self.theme.display_wrapStyle))
422- theme = new_theme.extract_xml()
423- pretty_theme = new_theme.extract_formatted_xml()
424- if self.thememanager.saveTheme(theme_name, theme, pretty_theme,
425- save_from, save_to) is not False:
426- return QtGui.QDialog.accept(self)
427-
428- def loadTheme(self, theme):
429- log.debug(u'LoadTheme %s', theme)
430- if theme == None:
431- self.theme.parse(self.baseTheme())
432- else:
433- xml_file = os.path.join(self.path, theme, theme + u'.xml')
434- xml = file_to_xml(xml_file)
435- self.theme.parse(xml)
436- self.theme.extend_image_filename(self.path)
437- self.cleanTheme(self.theme)
438- self.allowPreview = False
439- self.paintUi(self.theme)
440- self.allowPreview = True
441- self.previewTheme(self.theme)
442-
443- def cleanTheme(self, theme):
444- self.theme.background_color = theme.background_color.strip()
445- self.theme.background_direction = theme.background_direction.strip()
446- self.theme.background_endColor = theme.background_endColor.strip()
447- if theme.background_filename:
448- self.theme.background_filename = theme.background_filename.strip()
449- #self.theme.background_mode
450- self.theme.background_startColor = theme.background_startColor.strip()
451- #self.theme.background_type
452- if theme.display_display:
453- self.theme.display_display = theme.display_display.strip()
454- self.theme.display_horizontalAlign = \
455- theme.display_horizontalAlign.strip()
456- self.theme.display_outline = str_to_bool(theme.display_outline)
457- #self.theme.display_outline_color
458- self.theme.display_shadow = str_to_bool(theme.display_shadow)
459- #self.theme.display_shadow_color
460- self.theme.display_verticalAlign = \
461- theme.display_verticalAlign.strip()
462- self.theme.display_wrapStyle = theme.display_wrapStyle.strip()
463- self.theme.font_footer_color = theme.font_footer_color.strip()
464- self.theme.font_footer_height = theme.font_footer_height.strip()
465- self.theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
466- self.theme.font_footer_name = theme.font_footer_name.strip()
467- #self.theme.font_footer_override
468- self.theme.font_footer_proportion = \
469- theme.font_footer_proportion.strip()
470- self.theme.font_footer_weight = theme.font_footer_weight.strip()
471- self.theme.font_footer_width = theme.font_footer_width.strip()
472- self.theme.font_footer_x = theme.font_footer_x.strip()
473- self.theme.font_footer_y = theme.font_footer_y.strip()
474- self.theme.font_main_color = theme.font_main_color.strip()
475- self.theme.font_main_height = theme.font_main_height.strip()
476- self.theme.font_main_italics = str_to_bool(theme.font_main_italics)
477- self.theme.font_main_name = theme.font_main_name.strip()
478- #self.theme.font_main_override
479- self.theme.font_main_proportion = theme.font_main_proportion.strip()
480- self.theme.font_main_weight = theme.font_main_weight.strip()
481- self.theme.font_main_x = theme.font_main_x.strip()
482- self.theme.font_main_y = theme.font_main_y.strip()
483- #self.theme.theme_mode
484- self.theme.theme_name = theme.theme_name.strip()
485- #self.theme.theme_version
486-
487- def onImageToolButtonClicked(self):
488- filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file')
489- if filename != "":
490- self.ImageLineEdit.setText(filename)
491- self.theme.background_filename = filename
492- self.previewTheme(self.theme)
493- #
494- #Main Font Tab
495- #
496- def onFontMainComboBoxSelected(self):
497- self.theme.font_main_name = self.FontMainComboBox.currentFont().family()
498- self.previewTheme(self.theme)
499-
500- def onFontMainWeightComboBoxSelected(self, value):
501- if value ==0:
502- self.theme.font_main_weight = u'Normal'
503- self.theme.font_main_italics = False
504- elif value == 1:
505- self.theme.font_main_weight = u'Bold'
506- self.theme.font_main_italics = False
507- elif value == 2:
508- self.theme.font_main_weight = u'Normal'
509- self.theme.font_main_italics = True
510- else:
511- self.theme.font_main_weight = u'Bold'
512- self.theme.font_main_italics = True
513- self.previewTheme(self.theme)
514-
515- def onFontMainColorPushButtonClicked(self):
516- self.theme.font_main_color = QtGui.QColorDialog.getColor(
517- QtGui.QColor(self.theme.font_main_color), self).name()
518-
519- self.FontMainColorPushButton.setStyleSheet(
520- u'background-color: %s' % unicode(self.theme.font_main_color))
521- self.previewTheme(self.theme)
522-
523- def onFontMainSizeSpinBoxChanged(self):
524- if self.theme.font_main_proportion != self.FontMainSizeSpinBox.value():
525- self.theme.font_main_proportion = self.FontMainSizeSpinBox.value()
526- self.previewTheme(self.theme)
527-
528- def onFontMainDefaultCheckBoxChanged(self, value):
529- if value == 2: # checked
530- self.theme.font_main_override = False
531- else:
532- self.theme.font_main_override = True
533-
534- if int(self.theme.font_main_x) == 0 and \
535- int(self.theme.font_main_y) == 0 and \
536- int(self.theme.font_main_width) == 0 and \
537- int(self.theme.font_main_height) == 0:
538- self.theme.font_main_x = u'10'
539- self.theme.font_main_y = u'10'
540- self.theme.font_main_width = u'1024'
541- self.theme.font_main_height = u'730'
542- self.FontMainXSpinBox.setValue(int(self.theme.font_main_x))
543- self.FontMainYSpinBox.setValue(int(self.theme.font_main_y))
544- self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width))
545- self.FontMainHeightSpinBox.setValue(int( \
546- self.theme.font_main_height))
547- self.stateChanging(self.theme)
548- self.previewTheme(self.theme)
549-
550- def onFontMainXSpinBoxChanged(self):
551- if self.theme.font_main_x != self.FontMainXSpinBox.value():
552- self.theme.font_main_x = self.FontMainXSpinBox.value()
553- self.previewTheme(self.theme)
554-
555- def onFontMainYSpinBoxChanged(self):
556- if self.theme.font_main_y != self.FontMainYSpinBox.value():
557- self.theme.font_main_y = self.FontMainYSpinBox.value()
558- self.previewTheme(self.theme)
559-
560- def onFontMainWidthSpinBoxChanged(self):
561- if self.theme.font_main_width != self.FontMainWidthSpinBox.value():
562- self.theme.font_main_width = self.FontMainWidthSpinBox.value()
563- self.previewTheme(self.theme)
564-
565- def onFontMainHeightSpinBoxChanged(self):
566- if self.theme.font_main_height != self.FontMainHeightSpinBox.value():
567- self.theme.font_main_height = self.FontMainHeightSpinBox.value()
568- self.previewTheme(self.theme)
569- #
570- #Footer Font Tab
571- #
572- def onFontFooterComboBoxSelected(self):
573- self.theme.font_footer_name = \
574- self.FontFooterComboBox.currentFont().family()
575- self.previewTheme(self.theme)
576-
577- def onFontFooterWeightComboBoxSelected(self, value):
578- if value == 0:
579- self.theme.font_footer_weight = u'Normal'
580- self.theme.font_footer_italics = False
581- elif value == 1:
582- self.theme.font_footer_weight = u'Bold'
583- self.theme.font_footer_italics = False
584- elif value == 2:
585- self.theme.font_footer_weight = u'Normal'
586- self.theme.font_footer_italics = True
587- else:
588- self.theme.font_footer_weight = u'Bold'
589- self.theme.font_footer_italics = True
590- self.previewTheme(self.theme)
591-
592- def onFontFooterColorPushButtonClicked(self):
593- self.theme.font_footer_color = QtGui.QColorDialog.getColor(
594- QtGui.QColor(self.theme.font_footer_color), self).name()
595-
596- self.FontFooterColorPushButton.setStyleSheet(
597- 'background-color: %s' % unicode(self.theme.font_footer_color))
598- self.previewTheme(self.theme)
599-
600- def onFontFooterSizeSpinBoxChanged(self):
601- if self.theme.font_footer_proportion != \
602- self.FontFooterSizeSpinBox.value():
603- self.theme.font_footer_proportion = \
604- self.FontFooterSizeSpinBox.value()
605- self.previewTheme(self.theme)
606-
607- def onFontFooterDefaultCheckBoxChanged(self, value):
608- if value == 2: # checked
609- self.theme.font_footer_override = False
610- else:
611- self.theme.font_footer_override = True
612-
613- if int(self.theme.font_footer_x) == 0 and \
614- int(self.theme.font_footer_y) == 0 and \
615- int(self.theme.font_footer_width) == 0 and \
616- int(self.theme.font_footer_height) == 0:
617- self.theme.font_footer_x = u'10'
618- self.theme.font_footer_y = u'730'
619- self.theme.font_footer_width = u'1024'
620- self.theme.font_footer_height = u'38'
621-
622- self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x))
623- self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y))
624- self.FontFooterWidthSpinBox.setValue(int( \
625- self.theme.font_footer_width))
626- self.FontFooterHeightSpinBox.setValue(int( \
627- self.theme.font_footer_height))
628-
629- self.stateChanging(self.theme)
630- self.previewTheme(self.theme)
631-
632- def onFontFooterXSpinBoxChanged(self):
633- if self.theme.font_footer_x != self.FontFooterXSpinBox.value():
634- self.theme.font_footer_x = self.FontFooterXSpinBox.value()
635- self.previewTheme(self.theme)
636-
637- def onFontFooterYSpinBoxChanged(self):
638- if self.theme.font_footer_y != self.FontFooterYSpinBox.value():
639- self.theme.font_footer_y = self.FontFooterYSpinBox.value()
640- self.previewTheme(self.theme)
641-
642- def onFontFooterWidthSpinBoxChanged(self):
643- if self.theme.font_footer_width != self.FontFooterWidthSpinBox.value():
644- self.theme.font_footer_width = self.FontFooterWidthSpinBox.value()
645- self.previewTheme(self.theme)
646-
647- def onFontFooterHeightSpinBoxChanged(self):
648- if self.theme.font_footer_height != \
649- self.FontFooterHeightSpinBox.value():
650- self.theme.font_footer_height = self.FontFooterHeightSpinBox.value()
651- self.previewTheme(self.theme)
652- #
653- #Background Tab
654- #
655- def onGradientComboBoxSelected(self, currentIndex):
656- self.setBackground(self.BackgroundTypeComboBox.currentIndex(),
657- currentIndex)
658-
659- def onBackgroundComboBoxSelected(self, currentIndex):
660- if currentIndex == 0: # Opaque
661- self.theme.background_mode = u'opaque'
662- else:
663- self.theme.background_mode = u'transparent'
664- self.stateChanging(self.theme)
665- self.previewTheme(self.theme)
666-
667- def onBackgroundTypeComboBoxSelected(self, currentIndex):
668- self.setBackground(currentIndex, self.GradientComboBox.currentIndex())
669-
670- def setBackground(self, background, gradient):
671- if background == 0: # Solid
672- self.theme.background_type = u'solid'
673- if self.theme.background_color is None :
674- self.theme.background_color = u'#000000'
675- elif background == 1: # Gradient
676- self.theme.background_type = u'gradient'
677- if gradient == 0: # Horizontal
678- self.theme.background_direction = u'horizontal'
679- elif gradient == 1: # vertical
680- self.theme.background_direction = u'vertical'
681- else:
682- self.theme.background_direction = u'circular'
683- if self.theme.background_startColor is None :
684- self.theme.background_startColor = u'#000000'
685- if self.theme.background_endColor is None :
686- self.theme.background_endColor = u'#ff0000'
687- else:
688- self.theme.background_type = u'image'
689- self.stateChanging(self.theme)
690- self.previewTheme(self.theme)
691-
692- def onColor1PushButtonClicked(self):
693- if self.theme.background_type == u'solid':
694- self.theme.background_color = QtGui.QColorDialog.getColor(
695- QtGui.QColor(self.theme.background_color), self).name()
696- self.Color1PushButton.setStyleSheet(
697- u'background-color: %s' % unicode(self.theme.background_color))
698- else:
699- self.theme.background_startColor = QtGui.QColorDialog.getColor(
700- QtGui.QColor(self.theme.background_startColor), self).name()
701- self.Color1PushButton.setStyleSheet(
702- u'background-color: %s' % \
703- unicode(self.theme.background_startColor))
704-
705- self.previewTheme(self.theme)
706-
707- def onColor2PushButtonClicked(self):
708- self.theme.background_endColor = QtGui.QColorDialog.getColor(
709- QtGui.QColor(self.theme.background_endColor), self).name()
710- self.Color2PushButton.setStyleSheet(
711- u'background-color: %s' % unicode(self.theme.background_endColor))
712-
713- self.previewTheme(self.theme)
714- #
715- #Other Tab
716- #
717- def onOutlineCheckBoxChanged(self, value):
718- if value == 2: # checked
719- self.theme.display_outline = True
720- else:
721- self.theme.display_outline = False
722- self.stateChanging(self.theme)
723- self.previewTheme(self.theme)
724-
725- def onOutlineColorPushButtonClicked(self):
726- self.theme.display_outline_color = QtGui.QColorDialog.getColor(
727- QtGui.QColor(self.theme.display_outline_color), self).name()
728- self.OutlineColorPushButton.setStyleSheet(
729- u'background-color: %s' % unicode(self.theme.display_outline_color))
730- self.previewTheme(self.theme)
731-
732- def onShadowCheckBoxChanged(self, value):
733- if value == 2: # checked
734- self.theme.display_shadow = True
735- else:
736- self.theme.display_shadow = False
737- self.stateChanging(self.theme)
738- self.previewTheme(self.theme)
739-
740- def onShadowColorPushButtonClicked(self):
741- self.theme.display_shadow_color = QtGui.QColorDialog.getColor(
742- QtGui.QColor(self.theme.display_shadow_color), self).name()
743- self.ShadowColorPushButton.setStyleSheet(
744- u'background-color: %s' % unicode(self.theme.display_shadow_color))
745- self.previewTheme(self.theme)
746-
747- def onHorizontalComboBoxSelected(self, currentIndex):
748- self.theme.display_horizontalAlign = currentIndex
749- self.stateChanging(self.theme)
750- self.previewTheme(self.theme)
751-
752- def onVerticalComboBoxSelected(self, currentIndex):
753- self.theme.display_verticalAlign = currentIndex
754- self.stateChanging(self.theme)
755- self.previewTheme(self.theme)
756- #
757- #Local Methods
758- #
759- def baseTheme(self):
760- log.debug(u'base theme created')
761- newtheme = ThemeXML()
762- newtheme.new_document(u'New Theme')
763- newtheme.add_background_solid(unicode(u'#000000'))
764- newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
765- unicode(30), u'False')
766- newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
767- unicode(12), u'False', u'footer')
768- newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
769- unicode(u'#FFFFFF'),
770- unicode(0), unicode(0), unicode(0))
771-
772- return newtheme.extract_xml()
773-
774- def paintUi(self, theme):
775- self.stateChanging(theme)
776- self.ThemeNameEdit.setText(self.theme.theme_name)
777- if self.theme.background_mode == u'opaque':
778- self.BackgroundComboBox.setCurrentIndex(0)
779- else:
780- self.BackgroundComboBox.setCurrentIndex(1)
781-
782- if theme.background_type == u'solid':
783- self.BackgroundTypeComboBox.setCurrentIndex(0)
784- elif theme.background_type == u'gradient':
785- self.BackgroundTypeComboBox.setCurrentIndex(1)
786- else:
787- self.BackgroundTypeComboBox.setCurrentIndex(2)
788-
789- if self.theme.background_direction == u'horizontal':
790- self.GradientComboBox.setCurrentIndex(0)
791- elif self.theme.background_direction == u'vertical':
792- self.GradientComboBox.setCurrentIndex(1)
793- else:
794- self.GradientComboBox.setCurrentIndex(2)
795-
796- self.FontMainSizeSpinBox.setValue(int(self.theme.font_main_proportion))
797- if not self.theme.font_main_italics and \
798- self.theme.font_main_weight == u'Normal':
799- self.FontMainWeightComboBox.setCurrentIndex(0)
800- elif not self.theme.font_main_italics and \
801- self.theme.font_main_weight == u'Bold':
802- self.FontMainWeightComboBox.setCurrentIndex(1)
803- elif self.theme.font_main_italics and \
804- self.theme.font_main_weight == u'Normal':
805- self.FontMainWeightComboBox.setCurrentIndex(2)
806- else:
807- self.FontMainWeightComboBox.setCurrentIndex(3)
808-
809- self.FontMainXSpinBox.setValue(int(self.theme.font_main_x))
810- self.FontMainYSpinBox.setValue(int(self.theme.font_main_y))
811- self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width))
812- self.FontMainHeightSpinBox.setValue(int(self.theme.font_main_height))
813- self.FontFooterSizeSpinBox.setValue(
814- int(self.theme.font_footer_proportion))
815- if not self.theme.font_footer_italics and \
816- self.theme.font_footer_weight == u'Normal':
817- self.FontFooterWeightComboBox.setCurrentIndex(0)
818- elif not self.theme.font_footer_italics and \
819- self.theme.font_footer_weight == u'Bold':
820- self.FontFooterWeightComboBox.setCurrentIndex(1)
821- elif self.theme.font_footer_italics and \
822- self.theme.font_footer_weight == u'Normal':
823- self.FontFooterWeightComboBox.setCurrentIndex(2)
824- else:
825- self.FontFooterWeightComboBox.setCurrentIndex(3)
826- self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x))
827- self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y))
828- self.FontFooterWidthSpinBox.setValue(int(self.theme.font_footer_width))
829- self.FontFooterHeightSpinBox.setValue(
830- int(self.theme.font_footer_height))
831- self.FontMainColorPushButton.setStyleSheet(
832- u'background-color: %s' % unicode(theme.font_main_color))
833- self.FontFooterColorPushButton.setStyleSheet(
834- u'background-color: %s' % unicode(theme.font_footer_color))
835-
836- if self.theme.font_main_override == False:
837- self.FontMainDefaultCheckBox.setChecked(True)
838- else:
839- self.FontMainDefaultCheckBox.setChecked(False)
840-
841- if self.theme.font_footer_override == False:
842- self.FontFooterDefaultCheckBox.setChecked(True)
843- else:
844- self.FontFooterDefaultCheckBox.setChecked(False)
845-
846- self.OutlineColorPushButton.setStyleSheet(
847- u'background-color: %s' % unicode(theme.display_outline_color))
848- self.ShadowColorPushButton.setStyleSheet(
849- u'background-color: %s' % unicode(theme.display_shadow_color))
850-
851- if self.theme.display_outline:
852- self.OutlineCheckBox.setChecked(True)
853- self.OutlineColorPushButton.setEnabled(True)
854- else:
855- self.OutlineCheckBox.setChecked(False)
856- self.OutlineColorPushButton.setEnabled(False)
857-
858- if self.theme.display_shadow:
859- self.ShadowCheckBox.setChecked(True)
860- self.ShadowColorPushButton.setEnabled(True)
861- else:
862- self.ShadowCheckBox.setChecked(False)
863- self.ShadowColorPushButton.setEnabled(False)
864-
865- self.HorizontalComboBox.setCurrentIndex(
866- int(self.theme.display_horizontalAlign))
867- self.VerticalComboBox.setCurrentIndex(
868- int(self.theme.display_verticalAlign))
869-
870- def stateChanging(self, theme):
871- if theme.background_mode == u'transparent':
872- self.Color1Label.setVisible(False)
873- self.Color1PushButton.setVisible(False)
874- self.Color2Label.setVisible(False)
875- self.Color2PushButton.setVisible(False)
876- self.ImageLabel.setVisible(False)
877- self.ImageLineEdit.setVisible(False)
878- self.ImageFilenameWidget.setVisible(False)
879- self.GradientLabel.setVisible(False)
880- self.GradientComboBox.setVisible(False)
881- self.BackgroundTypeComboBox.setVisible(False)
882- self.BackgroundTypeLabel.setVisible(False)
883- else:
884- self.BackgroundTypeComboBox.setVisible(True)
885- self.BackgroundTypeLabel.setVisible(True)
886- if theme.background_type == u'solid':
887- self.Color1PushButton.setStyleSheet(
888- u'background-color: %s' % unicode(theme.background_color))
889- self.Color1Label.setText(translate(u'ThemeManager',
890- u'Background Color:'))
891- self.Color1Label.setVisible(True)
892- self.Color1PushButton.setVisible(True)
893- self.Color2Label.setVisible(False)
894- self.Color2PushButton.setVisible(False)
895- self.ImageLabel.setVisible(False)
896- self.ImageLineEdit.setVisible(False)
897- self.ImageFilenameWidget.setVisible(False)
898- self.GradientLabel.setVisible(False)
899- self.GradientComboBox.setVisible(False)
900- elif theme.background_type == u'gradient':
901- self.Color1PushButton.setStyleSheet(u'background-color: %s' \
902- % unicode(theme.background_startColor))
903- self.Color2PushButton.setStyleSheet(u'background-color: %s' \
904- % unicode(theme.background_endColor))
905- self.Color1Label.setText(translate(u'ThemeManager',
906- u'First Color:'))
907- self.Color2Label.setText(translate(u'ThemeManager',
908- u'Second Color:'))
909- self.Color1Label.setVisible(True)
910- self.Color1PushButton.setVisible(True)
911- self.Color2Label.setVisible(True)
912- self.Color2PushButton.setVisible(True)
913- self.ImageLabel.setVisible(False)
914- self.ImageLineEdit.setVisible(False)
915- self.ImageFilenameWidget.setVisible(False)
916- self.GradientLabel.setVisible(True)
917- self.GradientComboBox.setVisible(True)
918- else: # must be image
919- self.Color1Label.setVisible(False)
920- self.Color1PushButton.setVisible(False)
921- self.Color2Label.setVisible(False)
922- self.Color2PushButton.setVisible(False)
923- self.ImageLabel.setVisible(True)
924- self.ImageLineEdit.setVisible(True)
925- self.ImageFilenameWidget.setVisible(True)
926- self.GradientLabel.setVisible(False)
927- self.GradientComboBox.setVisible(False)
928-
929- if theme.font_main_override == False:
930- self.FontMainXSpinBox.setEnabled(False)
931- self.FontMainYSpinBox.setEnabled(False)
932- self.FontMainWidthSpinBox.setEnabled(False)
933- self.FontMainHeightSpinBox.setEnabled(False)
934- else:
935- self.FontMainXSpinBox.setEnabled(True)
936- self.FontMainYSpinBox.setEnabled(True)
937- self.FontMainWidthSpinBox.setEnabled(True)
938- self.FontMainHeightSpinBox.setEnabled(True)
939-
940- if theme.font_footer_override == False:
941- self.FontFooterXSpinBox.setEnabled(False)
942- self.FontFooterYSpinBox.setEnabled(False)
943- self.FontFooterWidthSpinBox.setEnabled(False)
944- self.FontFooterHeightSpinBox.setEnabled(False)
945- else:
946- self.FontFooterXSpinBox.setEnabled(True)
947- self.FontFooterYSpinBox.setEnabled(True)
948- self.FontFooterWidthSpinBox.setEnabled(True)
949- self.FontFooterHeightSpinBox.setEnabled(True)
950-
951- if self.theme.display_outline:
952- self.OutlineColorPushButton.setEnabled(True)
953- else:
954- self.OutlineColorPushButton.setEnabled(False)
955-
956- if self.theme.display_shadow:
957- self.ShadowColorPushButton.setEnabled(True)
958- else:
959- self.ShadowColorPushButton.setEnabled(False)
960-
961- def previewTheme(self, theme):
962- if self.allowPreview:
963- frame = self.thememanager.generateImage(theme)
964- self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
965+# -*- coding: utf-8 -*-
966+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
967+
968+###############################################################################
969+# OpenLP - Open Source Lyrics Projection #
970+# --------------------------------------------------------------------------- #
971+# Copyright (c) 2008-2009 Raoul Snyman #
972+# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
973+# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
974+# --------------------------------------------------------------------------- #
975+# This program is free software; you can redistribute it and/or modify it #
976+# under the terms of the GNU General Public License as published by the Free #
977+# Software Foundation; version 2 of the License. #
978+# #
979+# This program is distributed in the hope that it will be useful, but WITHOUT #
980+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
981+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
982+# more details. #
983+# #
984+# You should have received a copy of the GNU General Public License along #
985+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
986+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
987+###############################################################################
988+
989+import logging
990+import os, os.path
991+
992+from PyQt4 import QtCore, QtGui
993+from openlp.core.lib import ThemeXML, Renderer, file_to_xml, str_to_bool, \
994+ translate
995+
996+from amendthemedialog import Ui_AmendThemeDialog
997+
998+log = logging.getLogger(u'AmendThemeForm')
999+
1000+class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
1001+
1002+ def __init__(self, thememanager, parent=None):
1003+ QtGui.QDialog.__init__(self, parent)
1004+ self.thememanager = thememanager
1005+ self.path = None
1006+ self.theme = ThemeXML()
1007+ self.setupUi(self)
1008+ #define signals
1009+ #Buttons
1010+ QtCore.QObject.connect(self.Color1PushButton ,
1011+ QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
1012+ QtCore.QObject.connect(self.Color2PushButton ,
1013+ QtCore.SIGNAL(u'pressed()'), self.onColor2PushButtonClicked)
1014+ QtCore.QObject.connect(self.FontMainColorPushButton,
1015+ QtCore.SIGNAL(u'pressed()'), self.onFontMainColorPushButtonClicked)
1016+ QtCore.QObject.connect(self.FontFooterColorPushButton,
1017+ QtCore.SIGNAL(u'pressed()'),
1018+ self.onFontFooterColorPushButtonClicked)
1019+ QtCore.QObject.connect(self.OutlineColorPushButton,
1020+ QtCore.SIGNAL(u'pressed()'), self.onOutlineColorPushButtonClicked)
1021+ QtCore.QObject.connect(self.ShadowColorPushButton,
1022+ QtCore.SIGNAL(u'pressed()'), self.onShadowColorPushButtonClicked)
1023+ QtCore.QObject.connect(self.ImageToolButton,
1024+ QtCore.SIGNAL(u'pressed()'), self.onImageToolButtonClicked)
1025+ #Combo boxes
1026+ QtCore.QObject.connect(self.BackgroundComboBox,
1027+ QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected)
1028+ QtCore.QObject.connect(self.BackgroundTypeComboBox,
1029+ QtCore.SIGNAL(u'activated(int)'),
1030+ self.onBackgroundTypeComboBoxSelected)
1031+ QtCore.QObject.connect(self.GradientComboBox,
1032+ QtCore.SIGNAL(u'activated(int)'), self.onGradientComboBoxSelected)
1033+ QtCore.QObject.connect(self.FontMainComboBox,
1034+ QtCore.SIGNAL(u'activated(int)'), self.onFontMainComboBoxSelected)
1035+ QtCore.QObject.connect(self.FontMainWeightComboBox,
1036+ QtCore.SIGNAL(u'activated(int)'),
1037+ self.onFontMainWeightComboBoxSelected)
1038+ QtCore.QObject.connect(self.FontFooterComboBox,
1039+ QtCore.SIGNAL(u'activated(int)'), self.onFontFooterComboBoxSelected)
1040+ QtCore.QObject.connect(self.FontFooterWeightComboBox,
1041+ QtCore.SIGNAL(u'activated(int)'),
1042+ self.onFontFooterWeightComboBoxSelected)
1043+ QtCore.QObject.connect(self.HorizontalComboBox,
1044+ QtCore.SIGNAL(u'activated(int)'), self.onHorizontalComboBoxSelected)
1045+ QtCore.QObject.connect(self.VerticalComboBox,
1046+ QtCore.SIGNAL(u'activated(int)'), self.onVerticalComboBoxSelected)
1047+ #Spin boxes
1048+ QtCore.QObject.connect(self.FontMainSizeSpinBox,
1049+ QtCore.SIGNAL(u'editingFinished()'),
1050+ self.onFontMainSizeSpinBoxChanged)
1051+ QtCore.QObject.connect(self.FontFooterSizeSpinBox,
1052+ QtCore.SIGNAL(u'editingFinished()'),
1053+ self.onFontFooterSizeSpinBoxChanged)
1054+ QtCore.QObject.connect(self.FontMainDefaultCheckBox,
1055+ QtCore.SIGNAL(u'stateChanged(int)'),
1056+ self.onFontMainDefaultCheckBoxChanged)
1057+ QtCore.QObject.connect(self.FontMainXSpinBox,
1058+ QtCore.SIGNAL(u'editingFinished()'), self.onFontMainXSpinBoxChanged)
1059+ QtCore.QObject.connect(self.FontMainYSpinBox,
1060+ QtCore.SIGNAL(u'editingFinished()'), self.onFontMainYSpinBoxChanged)
1061+ QtCore.QObject.connect(self.FontMainWidthSpinBox,
1062+ QtCore.SIGNAL(u'editingFinished()'),
1063+ self.onFontMainWidthSpinBoxChanged)
1064+ QtCore.QObject.connect(self.FontMainHeightSpinBox,
1065+ QtCore.SIGNAL(u'editingFinished()'),
1066+ self.onFontMainHeightSpinBoxChanged)
1067+ QtCore.QObject.connect(self.FontFooterDefaultCheckBox,
1068+ QtCore.SIGNAL(u'stateChanged(int)'),
1069+ self.onFontFooterDefaultCheckBoxChanged)
1070+ QtCore.QObject.connect(self.FontFooterXSpinBox,
1071+ QtCore.SIGNAL(u'editingFinished()'),
1072+ self.onFontFooterXSpinBoxChanged)
1073+ QtCore.QObject.connect(self.FontFooterYSpinBox,
1074+ QtCore.SIGNAL(u'editingFinished()'),
1075+ self.onFontFooterYSpinBoxChanged)
1076+ QtCore.QObject.connect(self.FontFooterWidthSpinBox,
1077+ QtCore.SIGNAL(u'editingFinished()'),
1078+ self.onFontFooterWidthSpinBoxChanged)
1079+ QtCore.QObject.connect(self.FontFooterHeightSpinBox,
1080+ QtCore.SIGNAL(u'editingFinished()'),
1081+ self.onFontFooterHeightSpinBoxChanged)
1082+ QtCore.QObject.connect(self.OutlineCheckBox,
1083+ QtCore.SIGNAL(u'stateChanged(int)'), self.onOutlineCheckBoxChanged)
1084+ QtCore.QObject.connect(self.ShadowCheckBox,
1085+ QtCore.SIGNAL(u'stateChanged(int)'), self.onShadowCheckBoxChanged)
1086+
1087+ def accept(self):
1088+ new_theme = ThemeXML()
1089+ theme_name = unicode(self.ThemeNameEdit.displayText())
1090+ new_theme.new_document(theme_name)
1091+ save_from = None
1092+ save_to = None
1093+ if self.theme.background_mode == u'transparent':
1094+ new_theme.add_background_transparent()
1095+ else:
1096+ if self.theme.background_type == u'solid':
1097+ new_theme.add_background_solid( \
1098+ unicode(self.theme.background_color))
1099+ elif self.theme.background_type == u'gradient':
1100+ new_theme.add_background_gradient( \
1101+ unicode(self.theme.background_startColor),
1102+ unicode(self.theme.background_endColor),
1103+ self.theme.background_direction)
1104+ else:
1105+ (path, filename) = \
1106+ os.path.split(unicode(self.theme.background_filename))
1107+ new_theme.add_background_image(filename)
1108+ save_to= os.path.join(self.path, theme_name, filename )
1109+ save_from = self.theme.background_filename
1110+
1111+ new_theme.add_font(unicode(self.theme.font_main_name),
1112+ unicode(self.theme.font_main_color),
1113+ unicode(self.theme.font_main_proportion),
1114+ unicode(self.theme.font_main_override), u'main',
1115+ unicode(self.theme.font_main_weight),
1116+ unicode(self.theme.font_main_italics),
1117+ unicode(self.theme.font_main_x),
1118+ unicode(self.theme.font_main_y),
1119+ unicode(self.theme.font_main_width),
1120+ unicode(self.theme.font_main_height))
1121+ new_theme.add_font(unicode(self.theme.font_footer_name),
1122+ unicode(self.theme.font_footer_color),
1123+ unicode(self.theme.font_footer_proportion),
1124+ unicode(self.theme.font_footer_override), u'footer',
1125+ unicode(self.theme.font_footer_weight),
1126+ unicode(self.theme.font_footer_italics),
1127+ unicode(self.theme.font_footer_x),
1128+ unicode(self.theme.font_footer_y),
1129+ unicode(self.theme.font_footer_width),
1130+ unicode(self.theme.font_footer_height) )
1131+ new_theme.add_display(unicode(self.theme.display_shadow),
1132+ unicode(self.theme.display_shadow_color),
1133+ unicode(self.theme.display_outline),
1134+ unicode(self.theme.display_outline_color),
1135+ unicode(self.theme.display_horizontalAlign),
1136+ unicode(self.theme.display_verticalAlign),
1137+ unicode(self.theme.display_wrapStyle))
1138+ theme = new_theme.extract_xml()
1139+ pretty_theme = new_theme.extract_formatted_xml()
1140+ if self.thememanager.saveTheme(theme_name, theme, pretty_theme,
1141+ save_from, save_to) is not False:
1142+ return QtGui.QDialog.accept(self)
1143+
1144+ def loadTheme(self, theme):
1145+ log.debug(u'LoadTheme %s', theme)
1146+ if theme == None:
1147+ self.theme.parse(self.baseTheme())
1148+ else:
1149+ xml_file = os.path.join(self.path, theme, theme + u'.xml')
1150+ xml = file_to_xml(xml_file)
1151+ self.theme.parse(xml)
1152+ self.theme.extend_image_filename(self.path)
1153+ self.cleanTheme(self.theme)
1154+ self.allowPreview = False
1155+ self.paintUi(self.theme)
1156+ self.allowPreview = True
1157+ self.previewTheme(self.theme)
1158+
1159+ def cleanTheme(self, theme):
1160+ self.theme.background_color = theme.background_color.strip()
1161+ self.theme.background_direction = theme.background_direction.strip()
1162+ self.theme.background_endColor = theme.background_endColor.strip()
1163+ if theme.background_filename:
1164+ self.theme.background_filename = theme.background_filename.strip()
1165+ #self.theme.background_mode
1166+ self.theme.background_startColor = theme.background_startColor.strip()
1167+ #self.theme.background_type
1168+ if theme.display_display:
1169+ self.theme.display_display = theme.display_display.strip()
1170+ self.theme.display_horizontalAlign = \
1171+ theme.display_horizontalAlign.strip()
1172+ self.theme.display_outline = str_to_bool(theme.display_outline)
1173+ #self.theme.display_outline_color
1174+ self.theme.display_shadow = str_to_bool(theme.display_shadow)
1175+ #self.theme.display_shadow_color
1176+ self.theme.display_verticalAlign = \
1177+ theme.display_verticalAlign.strip()
1178+ self.theme.display_wrapStyle = theme.display_wrapStyle.strip()
1179+ self.theme.font_footer_color = theme.font_footer_color.strip()
1180+ self.theme.font_footer_height = theme.font_footer_height.strip()
1181+ self.theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
1182+ self.theme.font_footer_name = theme.font_footer_name.strip()
1183+ #self.theme.font_footer_override
1184+ self.theme.font_footer_proportion = \
1185+ theme.font_footer_proportion.strip()
1186+ self.theme.font_footer_weight = theme.font_footer_weight.strip()
1187+ self.theme.font_footer_width = theme.font_footer_width.strip()
1188+ self.theme.font_footer_x = theme.font_footer_x.strip()
1189+ self.theme.font_footer_y = theme.font_footer_y.strip()
1190+ self.theme.font_main_color = theme.font_main_color.strip()
1191+ self.theme.font_main_height = theme.font_main_height.strip()
1192+ self.theme.font_main_italics = str_to_bool(theme.font_main_italics)
1193+ self.theme.font_main_name = theme.font_main_name.strip()
1194+ #self.theme.font_main_override
1195+ self.theme.font_main_proportion = theme.font_main_proportion.strip()
1196+ self.theme.font_main_weight = theme.font_main_weight.strip()
1197+ self.theme.font_main_x = theme.font_main_x.strip()
1198+ self.theme.font_main_y = theme.font_main_y.strip()
1199+ #self.theme.theme_mode
1200+ self.theme.theme_name = theme.theme_name.strip()
1201+ #self.theme.theme_version
1202+
1203+ def onImageToolButtonClicked(self):
1204+ filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file')
1205+ if filename != "":
1206+ self.ImageLineEdit.setText(filename)
1207+ self.theme.background_filename = filename
1208+ self.previewTheme(self.theme)
1209+ #
1210+ #Main Font Tab
1211+ #
1212+ def onFontMainComboBoxSelected(self):
1213+ self.theme.font_main_name = self.FontMainComboBox.currentFont().family()
1214+ self.previewTheme(self.theme)
1215+
1216+ def onFontMainWeightComboBoxSelected(self, value):
1217+ if value ==0:
1218+ self.theme.font_main_weight = u'Normal'
1219+ self.theme.font_main_italics = False
1220+ elif value == 1:
1221+ self.theme.font_main_weight = u'Bold'
1222+ self.theme.font_main_italics = False
1223+ elif value == 2:
1224+ self.theme.font_main_weight = u'Normal'
1225+ self.theme.font_main_italics = True
1226+ else:
1227+ self.theme.font_main_weight = u'Bold'
1228+ self.theme.font_main_italics = True
1229+ self.previewTheme(self.theme)
1230+
1231+ def onFontMainColorPushButtonClicked(self):
1232+ self.theme.font_main_color = QtGui.QColorDialog.getColor(
1233+ QtGui.QColor(self.theme.font_main_color), self).name()
1234+
1235+ self.FontMainColorPushButton.setStyleSheet(
1236+ u'background-color: %s' % unicode(self.theme.font_main_color))
1237+ self.previewTheme(self.theme)
1238+
1239+ def onFontMainSizeSpinBoxChanged(self):
1240+ if self.theme.font_main_proportion != self.FontMainSizeSpinBox.value():
1241+ self.theme.font_main_proportion = self.FontMainSizeSpinBox.value()
1242+ self.previewTheme(self.theme)
1243+
1244+ def onFontMainDefaultCheckBoxChanged(self, value):
1245+ if value == 2: # checked
1246+ self.theme.font_main_override = False
1247+ else:
1248+ self.theme.font_main_override = True
1249+
1250+ if int(self.theme.font_main_x) == 0 and \
1251+ int(self.theme.font_main_y) == 0 and \
1252+ int(self.theme.font_main_width) == 0 and \
1253+ int(self.theme.font_main_height) == 0:
1254+ self.theme.font_main_x = u'10'
1255+ self.theme.font_main_y = u'10'
1256+ self.theme.font_main_width = u'1024'
1257+ self.theme.font_main_height = u'730'
1258+ self.FontMainXSpinBox.setValue(int(self.theme.font_main_x))
1259+ self.FontMainYSpinBox.setValue(int(self.theme.font_main_y))
1260+ self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width))
1261+ self.FontMainHeightSpinBox.setValue(int( \
1262+ self.theme.font_main_height))
1263+ self.stateChanging(self.theme)
1264+ self.previewTheme(self.theme)
1265+
1266+ def onFontMainXSpinBoxChanged(self):
1267+ if self.theme.font_main_x != self.FontMainXSpinBox.value():
1268+ self.theme.font_main_x = self.FontMainXSpinBox.value()
1269+ self.previewTheme(self.theme)
1270+
1271+ def onFontMainYSpinBoxChanged(self):
1272+ if self.theme.font_main_y != self.FontMainYSpinBox.value():
1273+ self.theme.font_main_y = self.FontMainYSpinBox.value()
1274+ self.previewTheme(self.theme)
1275+
1276+ def onFontMainWidthSpinBoxChanged(self):
1277+ if self.theme.font_main_width != self.FontMainWidthSpinBox.value():
1278+ self.theme.font_main_width = self.FontMainWidthSpinBox.value()
1279+ self.previewTheme(self.theme)
1280+
1281+ def onFontMainHeightSpinBoxChanged(self):
1282+ if self.theme.font_main_height != self.FontMainHeightSpinBox.value():
1283+ self.theme.font_main_height = self.FontMainHeightSpinBox.value()
1284+ self.previewTheme(self.theme)
1285+ #
1286+ #Footer Font Tab
1287+ #
1288+ def onFontFooterComboBoxSelected(self):
1289+ self.theme.font_footer_name = \
1290+ self.FontFooterComboBox.currentFont().family()
1291+ self.previewTheme(self.theme)
1292+
1293+ def onFontFooterWeightComboBoxSelected(self, value):
1294+ if value == 0:
1295+ self.theme.font_footer_weight = u'Normal'
1296+ self.theme.font_footer_italics = False
1297+ elif value == 1:
1298+ self.theme.font_footer_weight = u'Bold'
1299+ self.theme.font_footer_italics = False
1300+ elif value == 2:
1301+ self.theme.font_footer_weight = u'Normal'
1302+ self.theme.font_footer_italics = True
1303+ else:
1304+ self.theme.font_footer_weight = u'Bold'
1305+ self.theme.font_footer_italics = True
1306+ self.previewTheme(self.theme)
1307+
1308+ def onFontFooterColorPushButtonClicked(self):
1309+ self.theme.font_footer_color = QtGui.QColorDialog.getColor(
1310+ QtGui.QColor(self.theme.font_footer_color), self).name()
1311+
1312+ self.FontFooterColorPushButton.setStyleSheet(
1313+ 'background-color: %s' % unicode(self.theme.font_footer_color))
1314+ self.previewTheme(self.theme)
1315+
1316+ def onFontFooterSizeSpinBoxChanged(self):
1317+ if self.theme.font_footer_proportion != \
1318+ self.FontFooterSizeSpinBox.value():
1319+ self.theme.font_footer_proportion = \
1320+ self.FontFooterSizeSpinBox.value()
1321+ self.previewTheme(self.theme)
1322+
1323+ def onFontFooterDefaultCheckBoxChanged(self, value):
1324+ if value == 2: # checked
1325+ self.theme.font_footer_override = False
1326+ else:
1327+ self.theme.font_footer_override = True
1328+
1329+ if int(self.theme.font_footer_x) == 0 and \
1330+ int(self.theme.font_footer_y) == 0 and \
1331+ int(self.theme.font_footer_width) == 0 and \
1332+ int(self.theme.font_footer_height) == 0:
1333+ self.theme.font_footer_x = u'10'
1334+ self.theme.font_footer_y = u'730'
1335+ self.theme.font_footer_width = u'1024'
1336+ self.theme.font_footer_height = u'38'
1337+
1338+ self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x))
1339+ self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y))
1340+ self.FontFooterWidthSpinBox.setValue(int( \
1341+ self.theme.font_footer_width))
1342+ self.FontFooterHeightSpinBox.setValue(int( \
1343+ self.theme.font_footer_height))
1344+
1345+ self.stateChanging(self.theme)
1346+ self.previewTheme(self.theme)
1347+
1348+ def onFontFooterXSpinBoxChanged(self):
1349+ if self.theme.font_footer_x != self.FontFooterXSpinBox.value():
1350+ self.theme.font_footer_x = self.FontFooterXSpinBox.value()
1351+ self.previewTheme(self.theme)
1352+
1353+ def onFontFooterYSpinBoxChanged(self):
1354+ if self.theme.font_footer_y != self.FontFooterYSpinBox.value():
1355+ self.theme.font_footer_y = self.FontFooterYSpinBox.value()
1356+ self.previewTheme(self.theme)
1357+
1358+ def onFontFooterWidthSpinBoxChanged(self):
1359+ if self.theme.font_footer_width != self.FontFooterWidthSpinBox.value():
1360+ self.theme.font_footer_width = self.FontFooterWidthSpinBox.value()
1361+ self.previewTheme(self.theme)
1362+
1363+ def onFontFooterHeightSpinBoxChanged(self):
1364+ if self.theme.font_footer_height != \
1365+ self.FontFooterHeightSpinBox.value():
1366+ self.theme.font_footer_height = self.FontFooterHeightSpinBox.value()
1367+ self.previewTheme(self.theme)
1368+ #
1369+ #Background Tab
1370+ #
1371+ def onGradientComboBoxSelected(self, currentIndex):
1372+ self.setBackground(self.BackgroundTypeComboBox.currentIndex(),
1373+ currentIndex)
1374+
1375+ def onBackgroundComboBoxSelected(self, currentIndex):
1376+ if currentIndex == 0: # Opaque
1377+ self.theme.background_mode = u'opaque'
1378+ else:
1379+ self.theme.background_mode = u'transparent'
1380+ self.stateChanging(self.theme)
1381+ self.previewTheme(self.theme)
1382+
1383+ def onBackgroundTypeComboBoxSelected(self, currentIndex):
1384+ self.setBackground(currentIndex, self.GradientComboBox.currentIndex())
1385+
1386+ def setBackground(self, background, gradient):
1387+ if background == 0: # Solid
1388+ self.theme.background_type = u'solid'
1389+ if self.theme.background_color is None :
1390+ self.theme.background_color = u'#000000'
1391+ elif background == 1: # Gradient
1392+ self.theme.background_type = u'gradient'
1393+ if gradient == 0: # Horizontal
1394+ self.theme.background_direction = u'horizontal'
1395+ elif gradient == 1: # vertical
1396+ self.theme.background_direction = u'vertical'
1397+ else:
1398+ self.theme.background_direction = u'circular'
1399+ if self.theme.background_startColor is None :
1400+ self.theme.background_startColor = u'#000000'
1401+ if self.theme.background_endColor is None :
1402+ self.theme.background_endColor = u'#ff0000'
1403+ else:
1404+ self.theme.background_type = u'image'
1405+ self.stateChanging(self.theme)
1406+ self.previewTheme(self.theme)
1407+
1408+ def onColor1PushButtonClicked(self):
1409+ if self.theme.background_type == u'solid':
1410+ self.theme.background_color = QtGui.QColorDialog.getColor(
1411+ QtGui.QColor(self.theme.background_color), self).name()
1412+ self.Color1PushButton.setStyleSheet(
1413+ u'background-color: %s' % unicode(self.theme.background_color))
1414+ else:
1415+ self.theme.background_startColor = QtGui.QColorDialog.getColor(
1416+ QtGui.QColor(self.theme.background_startColor), self).name()
1417+ self.Color1PushButton.setStyleSheet(
1418+ u'background-color: %s' % \
1419+ unicode(self.theme.background_startColor))
1420+
1421+ self.previewTheme(self.theme)
1422+
1423+ def onColor2PushButtonClicked(self):
1424+ self.theme.background_endColor = QtGui.QColorDialog.getColor(
1425+ QtGui.QColor(self.theme.background_endColor), self).name()
1426+ self.Color2PushButton.setStyleSheet(
1427+ u'background-color: %s' % unicode(self.theme.background_endColor))
1428+
1429+ self.previewTheme(self.theme)
1430+ #
1431+ #Other Tab
1432+ #
1433+ def onOutlineCheckBoxChanged(self, value):
1434+ if value == 2: # checked
1435+ self.theme.display_outline = True
1436+ else:
1437+ self.theme.display_outline = False
1438+ self.stateChanging(self.theme)
1439+ self.previewTheme(self.theme)
1440+
1441+ def onOutlineColorPushButtonClicked(self):
1442+ self.theme.display_outline_color = QtGui.QColorDialog.getColor(
1443+ QtGui.QColor(self.theme.display_outline_color), self).name()
1444+ self.OutlineColorPushButton.setStyleSheet(
1445+ u'background-color: %s' % unicode(self.theme.display_outline_color))
1446+ self.previewTheme(self.theme)
1447+
1448+ def onShadowCheckBoxChanged(self, value):
1449+ if value == 2: # checked
1450+ self.theme.display_shadow = True
1451+ else:
1452+ self.theme.display_shadow = False
1453+ self.stateChanging(self.theme)
1454+ self.previewTheme(self.theme)
1455+
1456+ def onShadowColorPushButtonClicked(self):
1457+ self.theme.display_shadow_color = QtGui.QColorDialog.getColor(
1458+ QtGui.QColor(self.theme.display_shadow_color), self).name()
1459+ self.ShadowColorPushButton.setStyleSheet(
1460+ u'background-color: %s' % unicode(self.theme.display_shadow_color))
1461+ self.previewTheme(self.theme)
1462+
1463+ def onHorizontalComboBoxSelected(self, currentIndex):
1464+ self.theme.display_horizontalAlign = currentIndex
1465+ self.stateChanging(self.theme)
1466+ self.previewTheme(self.theme)
1467+
1468+ def onVerticalComboBoxSelected(self, currentIndex):
1469+ self.theme.display_verticalAlign = currentIndex
1470+ self.stateChanging(self.theme)
1471+ self.previewTheme(self.theme)
1472+ #
1473+ #Local Methods
1474+ #
1475+ def baseTheme(self):
1476+ log.debug(u'base theme created')
1477+ newtheme = ThemeXML()
1478+ newtheme.new_document(u'New Theme')
1479+ newtheme.add_background_solid(unicode(u'#000000'))
1480+ newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
1481+ unicode(30), u'False')
1482+ newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
1483+ unicode(12), u'False', u'footer')
1484+ newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
1485+ unicode(u'#FFFFFF'),
1486+ unicode(0), unicode(0), unicode(0))
1487+
1488+ return newtheme.extract_xml()
1489+
1490+ def paintUi(self, theme):
1491+ self.stateChanging(theme)
1492+ self.ThemeNameEdit.setText(self.theme.theme_name)
1493+ if self.theme.background_mode == u'opaque':
1494+ self.BackgroundComboBox.setCurrentIndex(0)
1495+ else:
1496+ self.BackgroundComboBox.setCurrentIndex(1)
1497+
1498+ if theme.background_type == u'solid':
1499+ self.BackgroundTypeComboBox.setCurrentIndex(0)
1500+ elif theme.background_type == u'gradient':
1501+ self.BackgroundTypeComboBox.setCurrentIndex(1)
1502+ else:
1503+ self.BackgroundTypeComboBox.setCurrentIndex(2)
1504+
1505+ if self.theme.background_direction == u'horizontal':
1506+ self.GradientComboBox.setCurrentIndex(0)
1507+ elif self.theme.background_direction == u'vertical':
1508+ self.GradientComboBox.setCurrentIndex(1)
1509+ else:
1510+ self.GradientComboBox.setCurrentIndex(2)
1511+
1512+ self.FontMainSizeSpinBox.setValue(int(self.theme.font_main_proportion))
1513+ if not self.theme.font_main_italics and \
1514+ self.theme.font_main_weight == u'Normal':
1515+ self.FontMainWeightComboBox.setCurrentIndex(0)
1516+ elif not self.theme.font_main_italics and \
1517+ self.theme.font_main_weight == u'Bold':
1518+ self.FontMainWeightComboBox.setCurrentIndex(1)
1519+ elif self.theme.font_main_italics and \
1520+ self.theme.font_main_weight == u'Normal':
1521+ self.FontMainWeightComboBox.setCurrentIndex(2)
1522+ else:
1523+ self.FontMainWeightComboBox.setCurrentIndex(3)
1524+
1525+ self.FontMainXSpinBox.setValue(int(self.theme.font_main_x))
1526+ self.FontMainYSpinBox.setValue(int(self.theme.font_main_y))
1527+ self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width))
1528+ self.FontMainHeightSpinBox.setValue(int(self.theme.font_main_height))
1529+ self.FontFooterSizeSpinBox.setValue(
1530+ int(self.theme.font_footer_proportion))
1531+ if not self.theme.font_footer_italics and \
1532+ self.theme.font_footer_weight == u'Normal':
1533+ self.FontFooterWeightComboBox.setCurrentIndex(0)
1534+ elif not self.theme.font_footer_italics and \
1535+ self.theme.font_footer_weight == u'Bold':
1536+ self.FontFooterWeightComboBox.setCurrentIndex(1)
1537+ elif self.theme.font_footer_italics and \
1538+ self.theme.font_footer_weight == u'Normal':
1539+ self.FontFooterWeightComboBox.setCurrentIndex(2)
1540+ else:
1541+ self.FontFooterWeightComboBox.setCurrentIndex(3)
1542+ self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x))
1543+ self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y))
1544+ self.FontFooterWidthSpinBox.setValue(int(self.theme.font_footer_width))
1545+ self.FontFooterHeightSpinBox.setValue(
1546+ int(self.theme.font_footer_height))
1547+ self.FontMainColorPushButton.setStyleSheet(
1548+ u'background-color: %s' % unicode(theme.font_main_color))
1549+ self.FontFooterColorPushButton.setStyleSheet(
1550+ u'background-color: %s' % unicode(theme.font_footer_color))
1551+
1552+ if self.theme.font_main_override == False:
1553+ self.FontMainDefaultCheckBox.setChecked(True)
1554+ else:
1555+ self.FontMainDefaultCheckBox.setChecked(False)
1556+
1557+ if self.theme.font_footer_override == False:
1558+ self.FontFooterDefaultCheckBox.setChecked(True)
1559+ else:
1560+ self.FontFooterDefaultCheckBox.setChecked(False)
1561+
1562+ self.OutlineColorPushButton.setStyleSheet(
1563+ u'background-color: %s' % unicode(theme.display_outline_color))
1564+ self.ShadowColorPushButton.setStyleSheet(
1565+ u'background-color: %s' % unicode(theme.display_shadow_color))
1566+
1567+ if self.theme.display_outline:
1568+ self.OutlineCheckBox.setChecked(True)
1569+ self.OutlineColorPushButton.setEnabled(True)
1570+ else:
1571+ self.OutlineCheckBox.setChecked(False)
1572+ self.OutlineColorPushButton.setEnabled(False)
1573+
1574+ if self.theme.display_shadow:
1575+ self.ShadowCheckBox.setChecked(True)
1576+ self.ShadowColorPushButton.setEnabled(True)
1577+ else:
1578+ self.ShadowCheckBox.setChecked(False)
1579+ self.ShadowColorPushButton.setEnabled(False)
1580+
1581+ self.HorizontalComboBox.setCurrentIndex(
1582+ int(self.theme.display_horizontalAlign))
1583+ self.VerticalComboBox.setCurrentIndex(
1584+ int(self.theme.display_verticalAlign))
1585+
1586+ def stateChanging(self, theme):
1587+ if theme.background_mode == u'transparent':
1588+ self.Color1Label.setVisible(False)
1589+ self.Color1PushButton.setVisible(False)
1590+ self.Color2Label.setVisible(False)
1591+ self.Color2PushButton.setVisible(False)
1592+ self.ImageLabel.setVisible(False)
1593+ self.ImageLineEdit.setVisible(False)
1594+ self.ImageFilenameWidget.setVisible(False)
1595+ self.GradientLabel.setVisible(False)
1596+ self.GradientComboBox.setVisible(False)
1597+ self.BackgroundTypeComboBox.setVisible(False)
1598+ self.BackgroundTypeLabel.setVisible(False)
1599+ else:
1600+ self.BackgroundTypeComboBox.setVisible(True)
1601+ self.BackgroundTypeLabel.setVisible(True)
1602+ if theme.background_type == u'solid':
1603+ self.Color1PushButton.setStyleSheet(
1604+ u'background-color: %s' % unicode(theme.background_color))
1605+ self.Color1Label.setText(translate(u'ThemeManager',
1606+ u'Background Color:'))
1607+ self.Color1Label.setVisible(True)
1608+ self.Color1PushButton.setVisible(True)
1609+ self.Color2Label.setVisible(False)
1610+ self.Color2PushButton.setVisible(False)
1611+ self.ImageLabel.setVisible(False)
1612+ self.ImageLineEdit.setVisible(False)
1613+ self.ImageFilenameWidget.setVisible(False)
1614+ self.GradientLabel.setVisible(False)
1615+ self.GradientComboBox.setVisible(False)
1616+ elif theme.background_type == u'gradient':
1617+ self.Color1PushButton.setStyleSheet(u'background-color: %s' \
1618+ % unicode(theme.background_startColor))
1619+ self.Color2PushButton.setStyleSheet(u'background-color: %s' \
1620+ % unicode(theme.background_endColor))
1621+ self.Color1Label.setText(translate(u'ThemeManager',
1622+ u'First Color:'))
1623+ self.Color2Label.setText(translate(u'ThemeManager',
1624+ u'Second Color:'))
1625+ self.Color1Label.setVisible(True)
1626+ self.Color1PushButton.setVisible(True)
1627+ self.Color2Label.setVisible(True)
1628+ self.Color2PushButton.setVisible(True)
1629+ self.ImageLabel.setVisible(False)
1630+ self.ImageLineEdit.setVisible(False)
1631+ self.ImageFilenameWidget.setVisible(False)
1632+ self.GradientLabel.setVisible(True)
1633+ self.GradientComboBox.setVisible(True)
1634+ else: # must be image
1635+ self.Color1Label.setVisible(False)
1636+ self.Color1PushButton.setVisible(False)
1637+ self.Color2Label.setVisible(False)
1638+ self.Color2PushButton.setVisible(False)
1639+ self.ImageLabel.setVisible(True)
1640+ self.ImageLineEdit.setVisible(True)
1641+ self.ImageFilenameWidget.setVisible(True)
1642+ self.GradientLabel.setVisible(False)
1643+ self.GradientComboBox.setVisible(False)
1644+
1645+ if theme.font_main_override == False:
1646+ self.FontMainXSpinBox.setEnabled(False)
1647+ self.FontMainYSpinBox.setEnabled(False)
1648+ self.FontMainWidthSpinBox.setEnabled(False)
1649+ self.FontMainHeightSpinBox.setEnabled(False)
1650+ else:
1651+ self.FontMainXSpinBox.setEnabled(True)
1652+ self.FontMainYSpinBox.setEnabled(True)
1653+ self.FontMainWidthSpinBox.setEnabled(True)
1654+ self.FontMainHeightSpinBox.setEnabled(True)
1655+
1656+ if theme.font_footer_override == False:
1657+ self.FontFooterXSpinBox.setEnabled(False)
1658+ self.FontFooterYSpinBox.setEnabled(False)
1659+ self.FontFooterWidthSpinBox.setEnabled(False)
1660+ self.FontFooterHeightSpinBox.setEnabled(False)
1661+ else:
1662+ self.FontFooterXSpinBox.setEnabled(True)
1663+ self.FontFooterYSpinBox.setEnabled(True)
1664+ self.FontFooterWidthSpinBox.setEnabled(True)
1665+ self.FontFooterHeightSpinBox.setEnabled(True)
1666+
1667+ if self.theme.display_outline:
1668+ self.OutlineColorPushButton.setEnabled(True)
1669+ else:
1670+ self.OutlineColorPushButton.setEnabled(False)
1671+
1672+ if self.theme.display_shadow:
1673+ self.ShadowColorPushButton.setEnabled(True)
1674+ else:
1675+ self.ShadowColorPushButton.setEnabled(False)
1676+
1677+ def previewTheme(self, theme):
1678+ if self.allowPreview:
1679+ frame = self.thememanager.generateImage(theme)
1680+ self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
1681
1682=== modified file 'openlp/core/ui/thememanager.py'
1683--- openlp/core/ui/thememanager.py 2009-09-13 14:12:38 +0000
1684+++ openlp/core/ui/thememanager.py 2009-09-13 15:14:45 +0000
1685@@ -1,462 +1,462 @@
1686-# -*- coding: utf-8 -*-
1687-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
1688-
1689-###############################################################################
1690-# OpenLP - Open Source Lyrics Projection #
1691-# --------------------------------------------------------------------------- #
1692-# Copyright (c) 2008-2009 Raoul Snyman #
1693-# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
1694-# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
1695-# --------------------------------------------------------------------------- #
1696-# This program is free software; you can redistribute it and/or modify it #
1697-# under the terms of the GNU General Public License as published by the Free #
1698-# Software Foundation; version 2 of the License. #
1699-# #
1700-# This program is distributed in the hope that it will be useful, but WITHOUT #
1701-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
1702-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
1703-# more details. #
1704-# #
1705-# You should have received a copy of the GNU General Public License along #
1706-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
1707-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1708-###############################################################################
1709-
1710-import os
1711-import sys
1712-import zipfile
1713-import shutil
1714-import logging
1715-
1716-from xml.etree.ElementTree import ElementTree, XML
1717-from PyQt4 import QtCore, QtGui
1718-
1719-from openlp.core.ui import AmendThemeForm, ServiceManager
1720-from openlp.core.theme import Theme
1721-from openlp.core.lib import PluginConfig, OpenLPToolbar, ThemeXML, Renderer, \
1722- translate, str_to_bool, file_to_xml, buildIcon, Receiver
1723-from openlp.core.utils import ConfigHelper
1724-
1725-class ThemeManager(QtGui.QWidget):
1726- """
1727- Manages the orders of Theme.
1728- """
1729- global log
1730- log = logging.getLogger(u'ThemeManager')
1731-
1732- def __init__(self, parent):
1733- QtGui.QWidget.__init__(self, parent)
1734- self.parent = parent
1735- self.Layout = QtGui.QVBoxLayout(self)
1736- self.Layout.setSpacing(0)
1737- self.Layout.setMargin(0)
1738- self.amendThemeForm = AmendThemeForm(self)
1739- self.Toolbar = OpenLPToolbar(self)
1740- self.Toolbar.addToolbarButton(
1741- translate(u'ThemeManager', u'New Theme'), u':/themes/theme_new.png',
1742- translate(u'ThemeManager', u'Create a new theme'), self.onAddTheme)
1743- self.Toolbar.addToolbarButton(
1744- translate(u'ThemeManager', u'Edit Theme'),
1745- u':/themes/theme_edit.png',
1746- translate(u'ThemeManager', u'Edit a theme'), self.onEditTheme)
1747- self.Toolbar.addToolbarButton(
1748- translate(u'ThemeManager', u'Delete Theme'),
1749- u':/themes/theme_delete.png',
1750- translate(u'ThemeManager', u'Delete a theme'), self.onDeleteTheme)
1751- self.Toolbar.addSeparator()
1752- self.Toolbar.addToolbarButton(
1753- translate(u'ThemeManager', u'Import Theme'),
1754- u':/themes/theme_import.png',
1755- translate(u'ThemeManager', u'Import a theme'), self.onImportTheme)
1756- self.Toolbar.addToolbarButton(
1757- translate(u'ThemeManager', u'Export Theme'),
1758- u':/themes/theme_export.png',
1759- translate(u'ThemeManager', u'Export a theme'), self.onExportTheme)
1760- self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
1761- self.Layout.addWidget(self.Toolbar)
1762- self.ThemeListWidget = QtGui.QListWidget(self)
1763- self.ThemeListWidget.setAlternatingRowColors(True)
1764- self.ThemeListWidget.setIconSize(QtCore.QSize(88,50))
1765- self.Layout.addWidget(self.ThemeListWidget)
1766- #Signals
1767- QtCore.QObject.connect(self.ThemeListWidget,
1768- QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
1769- self.changeGlobalFromScreen)
1770- QtCore.QObject.connect(Receiver.get_receiver(),
1771- QtCore.SIGNAL(u'update_global_theme'), self.changeGlobalFromTab)
1772- #Variables
1773- self.themelist = []
1774- self.path = os.path.join(ConfigHelper.get_data_path(), u'themes')
1775- self.checkThemesExists(self.path)
1776- self.amendThemeForm.path = self.path
1777- # Last little bits of setting up
1778- self.config = PluginConfig(u'themes')
1779- self.servicePath = self.config.get_data_path()
1780- self.global_theme = unicode(
1781- self.config.get_config(u'theme global theme', u''))
1782-
1783- def changeGlobalFromTab(self, themeName):
1784- log.debug(u'changeGlobalFromTab %s', themeName)
1785- for count in range (0, self.ThemeListWidget.count()):
1786- #reset the old name
1787- item = self.ThemeListWidget.item(count)
1788- oldName = item.text()
1789- newName = unicode(item.data(QtCore.Qt.UserRole).toString())
1790- if oldName != newName:
1791- self.ThemeListWidget.item(count).setText(newName)
1792- #Set the new name
1793- if themeName == newName:
1794- name = u'%s (%s)' % (newName, translate(u'ThemeManager',
1795- u'default'))
1796- self.ThemeListWidget.item(count).setText(name)
1797-
1798- def changeGlobalFromScreen(self, index):
1799- log.debug(u'changeGlobalFromScreen %s', index)
1800- for count in range (0, self.ThemeListWidget.count()):
1801- item = self.ThemeListWidget.item(count)
1802- oldName = item.text()
1803- #reset the old name
1804- if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
1805- self.ThemeListWidget.item(count).setText(
1806- unicode(item.data(QtCore.Qt.UserRole).toString()))
1807- #Set the new name
1808- if count == index.row():
1809- self.global_theme = unicode(
1810- self.ThemeListWidget.item(count).text())
1811- name = u'%s (%s)' % (self.global_theme,
1812- translate(u'ThemeManager', u'default'))
1813- self.ThemeListWidget.item(count).setText(name)
1814- self.config.set_config(u'theme global theme', self.global_theme)
1815- Receiver().send_message(u'update_global_theme',
1816- self.global_theme)
1817- self.pushThemes()
1818-
1819- def onAddTheme(self):
1820- self.amendThemeForm.theme.parse(self.baseTheme())
1821- self.amendThemeForm.loadTheme(None)
1822- self.amendThemeForm.exec_()
1823-
1824- def onEditTheme(self):
1825- item = self.ThemeListWidget.currentItem()
1826- if item is not None:
1827- self.amendThemeForm.loadTheme(
1828- unicode(item.data(QtCore.Qt.UserRole).toString()))
1829- self.amendThemeForm.exec_()
1830-
1831- def onDeleteTheme(self):
1832- self.global_theme = unicode(
1833- self.config.get_config(u'theme global theme', u''))
1834- item = self.ThemeListWidget.currentItem()
1835- if item is not None:
1836- theme = unicode(item.text())
1837- # should be the same unless default
1838- if theme != unicode(item.data(QtCore.Qt.UserRole).toString()):
1839- QtGui.QMessageBox.critical(self,
1840- translate(u'ThemeManager', u'Error'),
1841- translate(u'ThemeManager',
1842- u'You are unable to delete the default theme!'),
1843- QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
1844- else:
1845- self.themelist.remove(theme)
1846- th = theme + u'.png'
1847- row = self.ThemeListWidget.row(item)
1848- self.ThemeListWidget.takeItem(row)
1849- try:
1850- os.remove(os.path.join(self.path, th))
1851- except:
1852- #if not present do not worry
1853- pass
1854- try:
1855- shutil.rmtree(os.path.join(self.path, theme))
1856- except:
1857- #if not present do not worry
1858- pass
1859- # As we do not reload the themes push out the change
1860- # Reaload the list as the internal lists and events need
1861- # to be triggered
1862- self.pushThemes()
1863-
1864- def onExportTheme(self):
1865- pass
1866-
1867- def onImportTheme(self):
1868- files = QtGui.QFileDialog.getOpenFileNames(None,
1869- translate(u'ThemeManager', u'Select Theme Import File'),
1870- self.path, u'Theme (*.*)')
1871- log.info(u'New Themes %s', unicode(files))
1872- if len(files) > 0:
1873- for file in files:
1874- self.unzipTheme(file, self.path)
1875- self.loadThemes()
1876-
1877- def loadThemes(self):
1878- """
1879- Loads the theme lists and triggers updates accross
1880- the whole system using direct calls or core functions
1881- and events for the plugins.
1882- The plugins will call back in to get the real list if they want it.
1883- """
1884- log.debug(u'Load themes from dir')
1885- self.themelist = []
1886- self.ThemeListWidget.clear()
1887- for root, dirs, files in os.walk(self.path):
1888- for name in files:
1889- if name.endswith(u'.png'):
1890- #check to see file is in theme root directory
1891- theme = os.path.join(self.path, name)
1892- if os.path.exists(theme):
1893- (path, filename) = os.path.split(unicode(file))
1894- textName = os.path.splitext(name)[0]
1895- if textName == self.global_theme:
1896- name = u'%s (%s)' % (textName,
1897- translate(u'ThemeManager', u'default'))
1898- else:
1899- name = textName
1900- item_name = QtGui.QListWidgetItem(name)
1901- item_name.setIcon(buildIcon(theme))
1902- item_name.setData(QtCore.Qt.UserRole,
1903- QtCore.QVariant(textName))
1904- self.ThemeListWidget.addItem(item_name)
1905- self.themelist.append(textName)
1906- self.pushThemes()
1907-
1908- def pushThemes(self):
1909- Receiver().send_message(u'update_themes', self.getThemes() )
1910-
1911- def getThemes(self):
1912- return self.themelist
1913-
1914- def getThemeData(self, themename):
1915- log.debug(u'getthemedata for theme %s', themename)
1916- xml_file = os.path.join(self.path, unicode(themename),
1917- unicode(themename) + u'.xml')
1918- try:
1919- xml = file_to_xml(xml_file)
1920- except:
1921- newtheme = ThemeXML()
1922- newtheme.new_document(u'New Theme')
1923- newtheme.add_background_solid(unicode(u'#000000'))
1924- newtheme.add_font(unicode(QtGui.QFont().family()),
1925- unicode(u'#FFFFFF'), unicode(30), u'False')
1926- newtheme.add_font(unicode(QtGui.QFont().family()),
1927- unicode(u'#FFFFFF'), unicode(12), u'False', u'footer')
1928- newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
1929- unicode(u'#FFFFFF'), unicode(0), unicode(0), unicode(0))
1930- xml = newtheme.extract_xml()
1931- theme = ThemeXML()
1932- theme.parse(xml)
1933- theme.extend_image_filename(self.path)
1934- self.cleanTheme(theme)
1935- return theme
1936-
1937- def checkThemesExists(self, dir):
1938- log.debug(u'check themes')
1939- if os.path.exists(dir) == False:
1940- os.mkdir(dir)
1941-
1942- def unzipTheme(self, filename, dir):
1943- """
1944- Unzip the theme, remove the preview file if stored
1945- Generate a new preview fileCheck the XML theme version and upgrade if
1946- necessary.
1947- """
1948- log.debug(u'Unzipping theme %s', filename)
1949- zip = zipfile.ZipFile(unicode(filename))
1950- filexml = None
1951- themename = None
1952- for file in zip.namelist():
1953- if file.endswith(os.path.sep):
1954- theme_dir = os.path.join(dir, file)
1955- if os.path.exists(theme_dir) == False:
1956- os.mkdir(os.path.join(dir, file))
1957- else:
1958- fullpath = os.path.join(dir, file)
1959- names = file.split(os.path.sep)
1960- if len(names) > 1:
1961- # not preview file
1962- if themename is None:
1963- themename = names[0]
1964- xml_data = zip.read(file)
1965- if os.path.splitext(file)[1].lower() in [u'.xml']:
1966- if self.checkVersion1(xml_data):
1967- # upgrade theme xml
1968- filexml = self.migrateVersion122(filename,
1969- fullpath, xml_data)
1970- else:
1971- filexml = xml_data
1972- outfile = open(fullpath, u'w')
1973- outfile.write(filexml)
1974- outfile.close()
1975- else:
1976- outfile = open(fullpath, u'w')
1977- outfile.write(zip.read(file))
1978- outfile.close()
1979- self.generateAndSaveImage(dir, themename, filexml)
1980-
1981- def checkVersion1(self, xmlfile):
1982- """
1983- Am I a version 1 theme
1984- """
1985- log.debug(u'checkVersion1 ')
1986- theme = xmlfile
1987- tree = ElementTree(element=XML(theme)).getroot()
1988- if tree.find(u'BackgroundType') is None:
1989- return False
1990- else:
1991- return True
1992-
1993- def migrateVersion122(self, filename, fullpath, xml_data):
1994- """
1995- Called by convert the xml data from version 1 format
1996- to the current format.
1997- New fields are defaulted but the new theme is useable
1998- """
1999- log.debug(u'migrateVersion122 %s %s', filename, fullpath)
2000- theme = Theme(xml_data)
2001- newtheme = ThemeXML()
2002- newtheme.new_document(theme.Name)
2003- if theme.BackgroundType == 0:
2004- newtheme.add_background_solid(unicode(
2005- theme.BackgroundParameter1.name()))
2006- elif theme.BackgroundType == 1:
2007- direction = u'vertical'
2008- if theme.BackgroundParameter3.name() == 1:
2009- direction = u'horizontal'
2010- newtheme.add_background_gradient(
2011- unicode(theme.BackgroundParameter1.name()),
2012- unicode(theme.BackgroundParameter2.name()), direction)
2013- else:
2014- newtheme.add_background_image(unicode(theme.BackgroundParameter1))
2015-
2016- newtheme.add_font(unicode(theme.FontName),
2017- unicode(theme.FontColor.name()),
2018- unicode(theme.FontProportion * 2), u'False')
2019- newtheme.add_font(unicode(theme.FontName),
2020- unicode(theme.FontColor.name()),
2021- unicode(12), u'False', u'footer')
2022- outline = False
2023- shadow = False
2024- if theme.Shadow == 1:
2025- shadow = True
2026- if theme.Outline == 1:
2027- outline = True
2028- newtheme.add_display(unicode(shadow), unicode(theme.ShadowColor.name()),
2029- unicode(outline), unicode(theme.OutlineColor.name()),
2030- unicode(theme.HorizontalAlign), unicode(theme.VerticalAlign),
2031- unicode(theme.WrapStyle))
2032- return newtheme.extract_xml()
2033-
2034- def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from,
2035- image_to) :
2036- """
2037- Called by thememaintenance Dialog to save the theme
2038- and to trigger the reload of the theme list
2039- """
2040- log.debug(u'saveTheme %s %s', name, theme_xml)
2041- theme_dir = os.path.join(self.path, name)
2042- if os.path.exists(theme_dir) == False:
2043- os.mkdir(os.path.join(self.path, name))
2044- theme_file = os.path.join(theme_dir, name + u'.xml')
2045- log.debug(theme_file)
2046-
2047- result = QtGui.QMessageBox.Yes
2048- if os.path.exists(theme_file):
2049- result = QtGui.QMessageBox.question(
2050- self,
2051- translate(u'ThemeManager', u'Theme Exists'),
2052- translate(u'ThemeManager', u'A theme with this name already exists, would you like to overwrite it?'),
2053- (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
2054- QtGui.QMessageBox.No)
2055- if result == QtGui.QMessageBox.Yes:
2056- # Save the theme, overwriting the existing theme if necessary.
2057- outfile = open(theme_file, u'w')
2058- outfile.write(theme_pretty_xml)
2059- outfile.close()
2060- if image_from is not None and image_from != image_to:
2061- shutil.copyfile(image_from, image_to)
2062-
2063- self.generateAndSaveImage(self.path, name, theme_xml)
2064- self.loadThemes()
2065- else:
2066- # Don't close the dialog - allow the user to change the name of
2067- # the theme or to cancel the theme dialog completely.
2068- return False
2069-
2070- def generateAndSaveImage(self, dir, name, theme_xml):
2071- log.debug(u'generateAndSaveImage %s %s %s', dir, name, theme_xml)
2072- theme = ThemeXML()
2073- theme.parse(theme_xml)
2074- theme.extend_image_filename(dir)
2075- frame = self.generateImage(theme)
2076- samplepathname = os.path.join(self.path, name + u'.png')
2077- if os.path.exists(samplepathname):
2078- os.unlink(samplepathname)
2079- frame.save(samplepathname, u'png')
2080- log.debug(u'Theme image written to %s', samplepathname)
2081-
2082- def generateImage(self, themedata):
2083- """
2084- Call the RenderManager to build a Sample Image
2085- """
2086- log.debug(u'generateImage %s ', themedata)
2087- frame = self.parent.RenderManager.generate_preview(themedata)
2088- return frame
2089-
2090- def getPreviewImage(self, theme):
2091- log.debug(u'getPreviewImage %s ', theme)
2092- image = os.path.join(self.path, theme + u'.png')
2093- return image
2094-
2095- def baseTheme(self):
2096- log.debug(u'base theme created')
2097- newtheme = ThemeXML()
2098- newtheme.new_document(u'New Theme')
2099- newtheme.add_background_solid(unicode(u'#000000'))
2100- newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
2101- unicode(30), u'False')
2102- newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
2103- unicode(12), u'False', u'footer')
2104- newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
2105- unicode(u'#FFFFFF'), unicode(0), unicode(0), unicode(0))
2106- return newtheme.extract_xml()
2107-
2108- def cleanTheme(self, theme):
2109- theme.background_color = theme.background_color.strip()
2110- theme.background_direction = theme.background_direction.strip()
2111- theme.background_endColor = theme.background_endColor.strip()
2112- if theme.background_filename:
2113- theme.background_filename = theme.background_filename.strip()
2114- #theme.background_mode
2115- theme.background_startColor = theme.background_startColor.strip()
2116- #theme.background_type
2117- if theme.display_display:
2118- theme.display_display = theme.display_display.strip()
2119- theme.display_horizontalAlign = theme.display_horizontalAlign.strip()
2120- theme.display_outline = str_to_bool(theme.display_outline)
2121- #theme.display_outline_color
2122- theme.display_shadow = str_to_bool(theme.display_shadow)
2123- #theme.display_shadow_color
2124- theme.display_verticalAlign = theme.display_verticalAlign.strip()
2125- theme.display_wrapStyle = theme.display_wrapStyle.strip()
2126- theme.font_footer_color = theme.font_footer_color.strip()
2127- theme.font_footer_height = theme.font_footer_height.strip()
2128- theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
2129- theme.font_footer_name = theme.font_footer_name.strip()
2130- #theme.font_footer_override
2131- theme.font_footer_proportion = theme.font_footer_proportion.strip()
2132- theme.font_footer_weight = theme.font_footer_weight.strip()
2133- theme.font_footer_width = theme.font_footer_width.strip()
2134- theme.font_footer_x = theme.font_footer_x.strip()
2135- theme.font_footer_y = theme.font_footer_y.strip()
2136- theme.font_main_color = theme.font_main_color.strip()
2137- theme.font_main_height = theme.font_main_height.strip()
2138- theme.font_main_italics = str_to_bool(theme.font_main_italics)
2139- theme.font_main_name = theme.font_main_name.strip()
2140- #theme.font_main_override
2141- theme.font_main_proportion = theme.font_main_proportion.strip()
2142- theme.font_main_weight = theme.font_main_weight.strip()
2143- theme.font_main_x = theme.font_main_x.strip()
2144- theme.font_main_y = theme.font_main_y.strip()
2145- #theme.theme_mode
2146- theme.theme_name = theme.theme_name.strip()
2147- #theme.theme_version
2148+# -*- coding: utf-8 -*-
2149+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
2150+
2151+###############################################################################
2152+# OpenLP - Open Source Lyrics Projection #
2153+# --------------------------------------------------------------------------- #
2154+# Copyright (c) 2008-2009 Raoul Snyman #
2155+# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
2156+# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
2157+# --------------------------------------------------------------------------- #
2158+# This program is free software; you can redistribute it and/or modify it #
2159+# under the terms of the GNU General Public License as published by the Free #
2160+# Software Foundation; version 2 of the License. #
2161+# #
2162+# This program is distributed in the hope that it will be useful, but WITHOUT #
2163+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
2164+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
2165+# more details. #
2166+# #
2167+# You should have received a copy of the GNU General Public License along #
2168+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
2169+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
2170+###############################################################################
2171+
2172+import os
2173+import sys
2174+import zipfile
2175+import shutil
2176+import logging
2177+
2178+from xml.etree.ElementTree import ElementTree, XML
2179+from PyQt4 import QtCore, QtGui
2180+
2181+from openlp.core.ui import AmendThemeForm, ServiceManager
2182+from openlp.core.theme import Theme
2183+from openlp.core.lib import PluginConfig, OpenLPToolbar, ThemeXML, Renderer, \
2184+ translate, str_to_bool, file_to_xml, buildIcon, Receiver
2185+from openlp.core.utils import ConfigHelper
2186+
2187+class ThemeManager(QtGui.QWidget):
2188+ """
2189+ Manages the orders of Theme.
2190+ """
2191+ global log
2192+ log = logging.getLogger(u'ThemeManager')
2193+
2194+ def __init__(self, parent):
2195+ QtGui.QWidget.__init__(self, parent)
2196+ self.parent = parent
2197+ self.Layout = QtGui.QVBoxLayout(self)
2198+ self.Layout.setSpacing(0)
2199+ self.Layout.setMargin(0)
2200+ self.amendThemeForm = AmendThemeForm(self)
2201+ self.Toolbar = OpenLPToolbar(self)
2202+ self.Toolbar.addToolbarButton(
2203+ translate(u'ThemeManager', u'New Theme'), u':/themes/theme_new.png',
2204+ translate(u'ThemeManager', u'Create a new theme'), self.onAddTheme)
2205+ self.Toolbar.addToolbarButton(
2206+ translate(u'ThemeManager', u'Edit Theme'),
2207+ u':/themes/theme_edit.png',
2208+ translate(u'ThemeManager', u'Edit a theme'), self.onEditTheme)
2209+ self.Toolbar.addToolbarButton(
2210+ translate(u'ThemeManager', u'Delete Theme'),
2211+ u':/themes/theme_delete.png',
2212+ translate(u'ThemeManager', u'Delete a theme'), self.onDeleteTheme)
2213+ self.Toolbar.addSeparator()
2214+ self.Toolbar.addToolbarButton(
2215+ translate(u'ThemeManager', u'Import Theme'),
2216+ u':/themes/theme_import.png',
2217+ translate(u'ThemeManager', u'Import a theme'), self.onImportTheme)
2218+ self.Toolbar.addToolbarButton(
2219+ translate(u'ThemeManager', u'Export Theme'),
2220+ u':/themes/theme_export.png',
2221+ translate(u'ThemeManager', u'Export a theme'), self.onExportTheme)
2222+ self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
2223+ self.Layout.addWidget(self.Toolbar)
2224+ self.ThemeListWidget = QtGui.QListWidget(self)
2225+ self.ThemeListWidget.setAlternatingRowColors(True)
2226+ self.ThemeListWidget.setIconSize(QtCore.QSize(88,50))
2227+ self.Layout.addWidget(self.ThemeListWidget)
2228+ #Signals
2229+ QtCore.QObject.connect(self.ThemeListWidget,
2230+ QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
2231+ self.changeGlobalFromScreen)
2232+ QtCore.QObject.connect(Receiver.get_receiver(),
2233+ QtCore.SIGNAL(u'update_global_theme'), self.changeGlobalFromTab)
2234+ #Variables
2235+ self.themelist = []
2236+ self.path = os.path.join(ConfigHelper.get_data_path(), u'themes')
2237+ self.checkThemesExists(self.path)
2238+ self.amendThemeForm.path = self.path
2239+ # Last little bits of setting up
2240+ self.config = PluginConfig(u'themes')
2241+ self.servicePath = self.config.get_data_path()
2242+ self.global_theme = unicode(
2243+ self.config.get_config(u'theme global theme', u''))
2244+
2245+ def changeGlobalFromTab(self, themeName):
2246+ log.debug(u'changeGlobalFromTab %s', themeName)
2247+ for count in range (0, self.ThemeListWidget.count()):
2248+ #reset the old name
2249+ item = self.ThemeListWidget.item(count)
2250+ oldName = item.text()
2251+ newName = unicode(item.data(QtCore.Qt.UserRole).toString())
2252+ if oldName != newName:
2253+ self.ThemeListWidget.item(count).setText(newName)
2254+ #Set the new name
2255+ if themeName == newName:
2256+ name = u'%s (%s)' % (newName, translate(u'ThemeManager',
2257+ u'default'))
2258+ self.ThemeListWidget.item(count).setText(name)
2259+
2260+ def changeGlobalFromScreen(self, index):
2261+ log.debug(u'changeGlobalFromScreen %s', index)
2262+ for count in range (0, self.ThemeListWidget.count()):
2263+ item = self.ThemeListWidget.item(count)
2264+ oldName = item.text()
2265+ #reset the old name
2266+ if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
2267+ self.ThemeListWidget.item(count).setText(
2268+ unicode(item.data(QtCore.Qt.UserRole).toString()))
2269+ #Set the new name
2270+ if count == index.row():
2271+ self.global_theme = unicode(
2272+ self.ThemeListWidget.item(count).text())
2273+ name = u'%s (%s)' % (self.global_theme,
2274+ translate(u'ThemeManager', u'default'))
2275+ self.ThemeListWidget.item(count).setText(name)
2276+ self.config.set_config(u'theme global theme', self.global_theme)
2277+ Receiver().send_message(u'update_global_theme',
2278+ self.global_theme)
2279+ self.pushThemes()
2280+
2281+ def onAddTheme(self):
2282+ self.amendThemeForm.theme.parse(self.baseTheme())
2283+ self.amendThemeForm.loadTheme(None)
2284+ self.amendThemeForm.exec_()
2285+
2286+ def onEditTheme(self):
2287+ item = self.ThemeListWidget.currentItem()
2288+ if item is not None:
2289+ self.amendThemeForm.loadTheme(
2290+ unicode(item.data(QtCore.Qt.UserRole).toString()))
2291+ self.amendThemeForm.exec_()
2292+
2293+ def onDeleteTheme(self):
2294+ self.global_theme = unicode(
2295+ self.config.get_config(u'theme global theme', u''))
2296+ item = self.ThemeListWidget.currentItem()
2297+ if item is not None:
2298+ theme = unicode(item.text())
2299+ # should be the same unless default
2300+ if theme != unicode(item.data(QtCore.Qt.UserRole).toString()):
2301+ QtGui.QMessageBox.critical(self,
2302+ translate(u'ThemeManager', u'Error'),
2303+ translate(u'ThemeManager',
2304+ u'You are unable to delete the default theme!'),
2305+ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
2306+ else:
2307+ self.themelist.remove(theme)
2308+ th = theme + u'.png'
2309+ row = self.ThemeListWidget.row(item)
2310+ self.ThemeListWidget.takeItem(row)
2311+ try:
2312+ os.remove(os.path.join(self.path, th))
2313+ except:
2314+ #if not present do not worry
2315+ pass
2316+ try:
2317+ shutil.rmtree(os.path.join(self.path, theme))
2318+ except:
2319+ #if not present do not worry
2320+ pass
2321+ # As we do not reload the themes push out the change
2322+ # Reaload the list as the internal lists and events need
2323+ # to be triggered
2324+ self.pushThemes()
2325+
2326+ def onExportTheme(self):
2327+ pass
2328+
2329+ def onImportTheme(self):
2330+ files = QtGui.QFileDialog.getOpenFileNames(None,
2331+ translate(u'ThemeManager', u'Select Theme Import File'),
2332+ self.path, u'Theme (*.*)')
2333+ log.info(u'New Themes %s', unicode(files))
2334+ if len(files) > 0:
2335+ for file in files:
2336+ self.unzipTheme(file, self.path)
2337+ self.loadThemes()
2338+
2339+ def loadThemes(self):
2340+ """
2341+ Loads the theme lists and triggers updates accross
2342+ the whole system using direct calls or core functions
2343+ and events for the plugins.
2344+ The plugins will call back in to get the real list if they want it.
2345+ """
2346+ log.debug(u'Load themes from dir')
2347+ self.themelist = []
2348+ self.ThemeListWidget.clear()
2349+ for root, dirs, files in os.walk(self.path):
2350+ for name in files:
2351+ if name.endswith(u'.png'):
2352+ #check to see file is in theme root directory
2353+ theme = os.path.join(self.path, name)
2354+ if os.path.exists(theme):
2355+ (path, filename) = os.path.split(unicode(file))
2356+ textName = os.path.splitext(name)[0]
2357+ if textName == self.global_theme:
2358+ name = u'%s (%s)' % (textName,
2359+ translate(u'ThemeManager', u'default'))
2360+ else:
2361+ name = textName
2362+ item_name = QtGui.QListWidgetItem(name)
2363+ item_name.setIcon(buildIcon(theme))
2364+ item_name.setData(QtCore.Qt.UserRole,
2365+ QtCore.QVariant(textName))
2366+ self.ThemeListWidget.addItem(item_name)
2367+ self.themelist.append(textName)
2368+ self.pushThemes()
2369+
2370+ def pushThemes(self):
2371+ Receiver().send_message(u'update_themes', self.getThemes() )
2372+
2373+ def getThemes(self):
2374+ return self.themelist
2375+
2376+ def getThemeData(self, themename):
2377+ log.debug(u'getthemedata for theme %s', themename)
2378+ xml_file = os.path.join(self.path, unicode(themename),
2379+ unicode(themename) + u'.xml')
2380+ try:
2381+ xml = file_to_xml(xml_file)
2382+ except:
2383+ newtheme = ThemeXML()
2384+ newtheme.new_document(u'New Theme')
2385+ newtheme.add_background_solid(unicode(u'#000000'))
2386+ newtheme.add_font(unicode(QtGui.QFont().family()),
2387+ unicode(u'#FFFFFF'), unicode(30), u'False')
2388+ newtheme.add_font(unicode(QtGui.QFont().family()),
2389+ unicode(u'#FFFFFF'), unicode(12), u'False', u'footer')
2390+ newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
2391+ unicode(u'#FFFFFF'), unicode(0), unicode(0), unicode(0))
2392+ xml = newtheme.extract_xml()
2393+ theme = ThemeXML()
2394+ theme.parse(xml)
2395+ theme.extend_image_filename(self.path)
2396+ self.cleanTheme(theme)
2397+ return theme
2398+
2399+ def checkThemesExists(self, dir):
2400+ log.debug(u'check themes')
2401+ if os.path.exists(dir) == False:
2402+ os.mkdir(dir)
2403+
2404+ def unzipTheme(self, filename, dir):
2405+ """
2406+ Unzip the theme, remove the preview file if stored
2407+ Generate a new preview fileCheck the XML theme version and upgrade if
2408+ necessary.
2409+ """
2410+ log.debug(u'Unzipping theme %s', filename)
2411+ zip = zipfile.ZipFile(unicode(filename))
2412+ filexml = None
2413+ themename = None
2414+ for file in zip.namelist():
2415+ if file.endswith(os.path.sep):
2416+ theme_dir = os.path.join(dir, file)
2417+ if os.path.exists(theme_dir) == False:
2418+ os.mkdir(os.path.join(dir, file))
2419+ else:
2420+ fullpath = os.path.join(dir, file)
2421+ names = file.split(os.path.sep)
2422+ if len(names) > 1:
2423+ # not preview file
2424+ if themename is None:
2425+ themename = names[0]
2426+ xml_data = zip.read(file)
2427+ if os.path.splitext(file)[1].lower() in [u'.xml']:
2428+ if self.checkVersion1(xml_data):
2429+ # upgrade theme xml
2430+ filexml = self.migrateVersion122(filename,
2431+ fullpath, xml_data)
2432+ else:
2433+ filexml = xml_data
2434+ outfile = open(fullpath, u'w')
2435+ outfile.write(filexml)
2436+ outfile.close()
2437+ else:
2438+ outfile = open(fullpath, u'w')
2439+ outfile.write(zip.read(file))
2440+ outfile.close()
2441+ self.generateAndSaveImage(dir, themename, filexml)
2442+
2443+ def checkVersion1(self, xmlfile):
2444+ """
2445+ Am I a version 1 theme
2446+ """
2447+ log.debug(u'checkVersion1 ')
2448+ theme = xmlfile
2449+ tree = ElementTree(element=XML(theme)).getroot()
2450+ if tree.find(u'BackgroundType') is None:
2451+ return False
2452+ else:
2453+ return True
2454+
2455+ def migrateVersion122(self, filename, fullpath, xml_data):
2456+ """
2457+ Called by convert the xml data from version 1 format
2458+ to the current format.
2459+ New fields are defaulted but the new theme is useable
2460+ """
2461+ log.debug(u'migrateVersion122 %s %s', filename, fullpath)
2462+ theme = Theme(xml_data)
2463+ newtheme = ThemeXML()
2464+ newtheme.new_document(theme.Name)
2465+ if theme.BackgroundType == 0:
2466+ newtheme.add_background_solid(unicode(
2467+ theme.BackgroundParameter1.name()))
2468+ elif theme.BackgroundType == 1:
2469+ direction = u'vertical'
2470+ if theme.BackgroundParameter3.name() == 1:
2471+ direction = u'horizontal'
2472+ newtheme.add_background_gradient(
2473+ unicode(theme.BackgroundParameter1.name()),
2474+ unicode(theme.BackgroundParameter2.name()), direction)
2475+ else:
2476+ newtheme.add_background_image(unicode(theme.BackgroundParameter1))
2477+
2478+ newtheme.add_font(unicode(theme.FontName),
2479+ unicode(theme.FontColor.name()),
2480+ unicode(theme.FontProportion * 2), u'False')
2481+ newtheme.add_font(unicode(theme.FontName),
2482+ unicode(theme.FontColor.name()),
2483+ unicode(12), u'False', u'footer')
2484+ outline = False
2485+ shadow = False
2486+ if theme.Shadow == 1:
2487+ shadow = True
2488+ if theme.Outline == 1:
2489+ outline = True
2490+ newtheme.add_display(unicode(shadow), unicode(theme.ShadowColor.name()),
2491+ unicode(outline), unicode(theme.OutlineColor.name()),
2492+ unicode(theme.HorizontalAlign), unicode(theme.VerticalAlign),
2493+ unicode(theme.WrapStyle))
2494+ return newtheme.extract_xml()
2495+
2496+ def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from,
2497+ image_to) :
2498+ """
2499+ Called by thememaintenance Dialog to save the theme
2500+ and to trigger the reload of the theme list
2501+ """
2502+ log.debug(u'saveTheme %s %s', name, theme_xml)
2503+ theme_dir = os.path.join(self.path, name)
2504+ if os.path.exists(theme_dir) == False:
2505+ os.mkdir(os.path.join(self.path, name))
2506+ theme_file = os.path.join(theme_dir, name + u'.xml')
2507+ log.debug(theme_file)
2508+
2509+ result = QtGui.QMessageBox.Yes
2510+ if os.path.exists(theme_file):
2511+ result = QtGui.QMessageBox.question(
2512+ self,
2513+ translate(u'ThemeManager', u'Theme Exists'),
2514+ translate(u'ThemeManager', u'A theme with this name already exists, would you like to overwrite it?'),
2515+ (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
2516+ QtGui.QMessageBox.No)
2517+ if result == QtGui.QMessageBox.Yes:
2518+ # Save the theme, overwriting the existing theme if necessary.
2519+ outfile = open(theme_file, u'w')
2520+ outfile.write(theme_pretty_xml)
2521+ outfile.close()
2522+ if image_from is not None and image_from != image_to:
2523+ shutil.copyfile(image_from, image_to)
2524+
2525+ self.generateAndSaveImage(self.path, name, theme_xml)
2526+ self.loadThemes()
2527+ else:
2528+ # Don't close the dialog - allow the user to change the name of
2529+ # the theme or to cancel the theme dialog completely.
2530+ return False
2531+
2532+ def generateAndSaveImage(self, dir, name, theme_xml):
2533+ log.debug(u'generateAndSaveImage %s %s %s', dir, name, theme_xml)
2534+ theme = ThemeXML()
2535+ theme.parse(theme_xml)
2536+ theme.extend_image_filename(dir)
2537+ frame = self.generateImage(theme)
2538+ samplepathname = os.path.join(self.path, name + u'.png')
2539+ if os.path.exists(samplepathname):
2540+ os.unlink(samplepathname)
2541+ frame.save(samplepathname, u'png')
2542+ log.debug(u'Theme image written to %s', samplepathname)
2543+
2544+ def generateImage(self, themedata):
2545+ """
2546+ Call the RenderManager to build a Sample Image
2547+ """
2548+ log.debug(u'generateImage %s ', themedata)
2549+ frame = self.parent.RenderManager.generate_preview(themedata)
2550+ return frame
2551+
2552+ def getPreviewImage(self, theme):
2553+ log.debug(u'getPreviewImage %s ', theme)
2554+ image = os.path.join(self.path, theme + u'.png')
2555+ return image
2556+
2557+ def baseTheme(self):
2558+ log.debug(u'base theme created')
2559+ newtheme = ThemeXML()
2560+ newtheme.new_document(u'New Theme')
2561+ newtheme.add_background_solid(unicode(u'#000000'))
2562+ newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
2563+ unicode(30), u'False')
2564+ newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'),
2565+ unicode(12), u'False', u'footer')
2566+ newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False',
2567+ unicode(u'#FFFFFF'), unicode(0), unicode(0), unicode(0))
2568+ return newtheme.extract_xml()
2569+
2570+ def cleanTheme(self, theme):
2571+ theme.background_color = theme.background_color.strip()
2572+ theme.background_direction = theme.background_direction.strip()
2573+ theme.background_endColor = theme.background_endColor.strip()
2574+ if theme.background_filename:
2575+ theme.background_filename = theme.background_filename.strip()
2576+ #theme.background_mode
2577+ theme.background_startColor = theme.background_startColor.strip()
2578+ #theme.background_type
2579+ if theme.display_display:
2580+ theme.display_display = theme.display_display.strip()
2581+ theme.display_horizontalAlign = theme.display_horizontalAlign.strip()
2582+ theme.display_outline = str_to_bool(theme.display_outline)
2583+ #theme.display_outline_color
2584+ theme.display_shadow = str_to_bool(theme.display_shadow)
2585+ #theme.display_shadow_color
2586+ theme.display_verticalAlign = theme.display_verticalAlign.strip()
2587+ theme.display_wrapStyle = theme.display_wrapStyle.strip()
2588+ theme.font_footer_color = theme.font_footer_color.strip()
2589+ theme.font_footer_height = theme.font_footer_height.strip()
2590+ theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
2591+ theme.font_footer_name = theme.font_footer_name.strip()
2592+ #theme.font_footer_override
2593+ theme.font_footer_proportion = theme.font_footer_proportion.strip()
2594+ theme.font_footer_weight = theme.font_footer_weight.strip()
2595+ theme.font_footer_width = theme.font_footer_width.strip()
2596+ theme.font_footer_x = theme.font_footer_x.strip()
2597+ theme.font_footer_y = theme.font_footer_y.strip()
2598+ theme.font_main_color = theme.font_main_color.strip()
2599+ theme.font_main_height = theme.font_main_height.strip()
2600+ theme.font_main_italics = str_to_bool(theme.font_main_italics)
2601+ theme.font_main_name = theme.font_main_name.strip()
2602+ #theme.font_main_override
2603+ theme.font_main_proportion = theme.font_main_proportion.strip()
2604+ theme.font_main_weight = theme.font_main_weight.strip()
2605+ theme.font_main_x = theme.font_main_x.strip()
2606+ theme.font_main_y = theme.font_main_y.strip()
2607+ #theme.theme_mode
2608+ theme.theme_name = theme.theme_name.strip()
2609+ #theme.theme_version
2610
2611=== modified file 'openlp/plugins/bibles/test/biblebooks_msg_short.csv'
2612--- openlp/plugins/bibles/test/biblebooks_msg_short.csv 2008-12-10 19:11:00 +0000
2613+++ openlp/plugins/bibles/test/biblebooks_msg_short.csv 2009-09-13 15:14:45 +0000
2614@@ -1,8 +1,8 @@
2615-1,1,"Genesis","GEN"
2616-2,1,"Exodus","EXOD"
2617-3,1,"Leviticus","LEV"
2618-4,1,"Numbers","NUM"
2619-47,2,"Matthew","MATT"
2620-48,2,"Mark","MARK"
2621-49,2,"Luke","LUKE"
2622-50,2,"John","JOHN"
2623+1,1,"Genesis","GEN"
2624+2,1,"Exodus","EXOD"
2625+3,1,"Leviticus","LEV"
2626+4,1,"Numbers","NUM"
2627+47,2,"Matthew","MATT"
2628+48,2,"Mark","MARK"
2629+49,2,"Luke","LUKE"
2630+50,2,"John","JOHN"
2631
2632=== modified file 'openlp/plugins/bibles/test/biblebooks_niv_short.csv'
2633--- openlp/plugins/bibles/test/biblebooks_niv_short.csv 2008-12-10 19:11:00 +0000
2634+++ openlp/plugins/bibles/test/biblebooks_niv_short.csv 2009-09-13 15:14:45 +0000
2635@@ -1,9 +1,9 @@
2636-1,1,"Genesis","GEN"
2637-2,1,"Exodus","EXOD"
2638-3,1,"Leviticus","LEV"
2639-4,1,"Numbers","NUM"
2640-46,1,"Malachi","MAL"
2641-47,2,"Matthew","MATT"
2642-48,2,"Mark","MARK"
2643-49,2,"Luke","LUKE"
2644-50,2,"John","JOHN"
2645+1,1,"Genesis","GEN"
2646+2,1,"Exodus","EXOD"
2647+3,1,"Leviticus","LEV"
2648+4,1,"Numbers","NUM"
2649+46,1,"Malachi","MAL"
2650+47,2,"Matthew","MATT"
2651+48,2,"Mark","MARK"
2652+49,2,"Luke","LUKE"
2653+50,2,"John","JOHN"
2654
2655=== modified file 'openlp/plugins/bibles/test/bibleverses_msg_short.csv'
2656--- openlp/plugins/bibles/test/bibleverses_msg_short.csv 2008-12-10 19:11:00 +0000
2657+++ openlp/plugins/bibles/test/bibleverses_msg_short.csv 2009-09-13 15:14:45 +0000
2658@@ -1,35 +1,35 @@
2659-"Genesis",1,1,"First this: God created the Heavens and Earth - all you see, all you don't see."
2660-"Genesis",1,2,"Earth was a soup of nothingness, a bottomless emptiness, an inky blackness. God's Spirit brooded like a bird above the watery abyss."
2661-"Exodus",1,1,"These are the names of the Israelites who went to Egypt with Jacob, each bringing his family members:"
2662-"Exodus",1,2,"Reuben, Simeon, Levi, and Judah,"
2663-"Exodus",2,1,"A man from the family of Levi married a Levite woman."
2664-"Exodus",2,2,"The woman became pregnant and had a son. She saw there was something special about him and hid him. She hid him for three months."
2665-"Leviticus",1,1,"God called Moses and spoke to him from the Tent of Meeting:"
2666-"Leviticus",1,2,"""Speak to the People of Israel. Tell them, When anyone presents an offering to God, present an animal from either the herd or the flock."
2667-"Leviticus",1,3,"""If the offering is a Whole-Burnt-Offering from the herd, present a male without a defect at the entrance to the Tent of Meeting that it may be accepted by God."
2668-"Numbers",1,1,"God spoke to Moses in the Wilderness of Sinai at the Tent of Meeting on the first day of the second month in the second year after they had left Egypt. He said,"
2669-"Numbers",1,2,"""Number the congregation of the People of Israel by clans and families, writing down the names of every male."
2670-"Matthew",1,1,"The family tree of Jesus Christ, David's son, Abraham's son:"
2671-"Matthew",1,2,"Abraham had Isaac, Isaac had Jacob, Jacob had Judah and his brothers,"
2672-"Matthew",1,3,"Judah had Perez and Zerah (the mother was Tamar), Perez had Hezron, Hezron had Aram,"
2673-"Matthew",1,4,"Aram had Amminadab, Amminadab had Nahshon, Nahshon had Salmon,"
2674-"Matthew",1,5,"Salmon had Boaz (his mother was Rahab), Boaz had Obed (Ruth was the mother), Obed had Jesse,"
2675-"Matthew",1,6,"Jesse had David, and David became king. David had Solomon (Uriah's wife was the mother),"
2676-"Matthew",1,7,"Solomon had Rehoboam, Rehoboam had Abijah, Abijah had Asa,"
2677-"Matthew",1,8,"Asa had Jehoshaphat, Jehoshaphat had Joram, Joram had Uzziah,"
2678-"Matthew",2,1,"After Jesus was born in Bethlehem village, Judah territory - this was during Herod's kingship - a band of scholars arrived in Jerusalem from the East."
2679-"Matthew",2,2,"They asked around, ""Where can we find and pay homage to the newborn King of the Jews? We observed a star in the eastern sky that "Matthew",3,1,"While Jesus was living in the Galilean hills, John, called ""the Baptizer,"" was preaching in the desert country of Judea."
2680-"Matthew",3,2,"His message was simple and austere, like his desert surroundings: ""Change your life. God's kingdom is here."""
2681-"Matthew",3,3,"John and his message were authorized by Isaiah's prophecy: Thunder in the desert! Prepare for God's arrival! Make the road smooth and straight!"
2682-"Mark",1,1,"The good news of Jesus Christ - the Message! - begins here,"
2683-"Mark",1,2,"following to the letter the scroll of the prophet Isaiah. Watch closely: I'm sending my preacher ahead of you; He'll make the road smooth for you."
2684-"Mark",1,3,"Thunder in the desert! Prepare for God's arrival! Make the road smooth and straight!"
2685-"Luke",1,1,"So many others have tried their hand at putting together a story of the wonderful harvest of Scripture and history that took place among us,"
2686-"Luke",1,2,"using reports handed down by the original eyewitnesses who served this Word with their very lives."
2687-"Luke",1,3,"Since I have investigated all the reports in close detail, starting from the story's beginning, I decided to write it all out for you, most honorable Theophilus,"
2688-"John",1,1,"The Word was first, the Word present to God, God present to the Word. The Word was God,"
2689-"John",1,2,"in readiness for God from day one."
2690-"John",1,3,"Everything was created through him; nothing - not one thing! - came into being without him."
2691-"John",2,1,"Three days later there was a wedding in the village of Cana in Galilee. Jesus' mother was there."
2692-"John",2,2,"Jesus and his disciples were guests also."
2693-"John",2,3,"When they started running low on wine at the wedding banquet, Jesus' mother told him, ""They're just about out of wine."""
2694+"Genesis",1,1,"First this: God created the Heavens and Earth - all you see, all you don't see."
2695+"Genesis",1,2,"Earth was a soup of nothingness, a bottomless emptiness, an inky blackness. God's Spirit brooded like a bird above the watery abyss."
2696+"Exodus",1,1,"These are the names of the Israelites who went to Egypt with Jacob, each bringing his family members:"
2697+"Exodus",1,2,"Reuben, Simeon, Levi, and Judah,"
2698+"Exodus",2,1,"A man from the family of Levi married a Levite woman."
2699+"Exodus",2,2,"The woman became pregnant and had a son. She saw there was something special about him and hid him. She hid him for three months."
2700+"Leviticus",1,1,"God called Moses and spoke to him from the Tent of Meeting:"
2701+"Leviticus",1,2,"""Speak to the People of Israel. Tell them, When anyone presents an offering to God, present an animal from either the herd or the flock."
2702+"Leviticus",1,3,"""If the offering is a Whole-Burnt-Offering from the herd, present a male without a defect at the entrance to the Tent of Meeting that it may be accepted by God."
2703+"Numbers",1,1,"God spoke to Moses in the Wilderness of Sinai at the Tent of Meeting on the first day of the second month in the second year after they had left Egypt. He said,"
2704+"Numbers",1,2,"""Number the congregation of the People of Israel by clans and families, writing down the names of every male."
2705+"Matthew",1,1,"The family tree of Jesus Christ, David's son, Abraham's son:"
2706+"Matthew",1,2,"Abraham had Isaac, Isaac had Jacob, Jacob had Judah and his brothers,"
2707+"Matthew",1,3,"Judah had Perez and Zerah (the mother was Tamar), Perez had Hezron, Hezron had Aram,"
2708+"Matthew",1,4,"Aram had Amminadab, Amminadab had Nahshon, Nahshon had Salmon,"
2709+"Matthew",1,5,"Salmon had Boaz (his mother was Rahab), Boaz had Obed (Ruth was the mother), Obed had Jesse,"
2710+"Matthew",1,6,"Jesse had David, and David became king. David had Solomon (Uriah's wife was the mother),"
2711+"Matthew",1,7,"Solomon had Rehoboam, Rehoboam had Abijah, Abijah had Asa,"
2712+"Matthew",1,8,"Asa had Jehoshaphat, Jehoshaphat had Joram, Joram had Uzziah,"
2713+"Matthew",2,1,"After Jesus was born in Bethlehem village, Judah territory - this was during Herod's kingship - a band of scholars arrived in Jerusalem from the East."
2714+"Matthew",2,2,"They asked around, ""Where can we find and pay homage to the newborn King of the Jews? We observed a star in the eastern sky that "Matthew",3,1,"While Jesus was living in the Galilean hills, John, called ""the Baptizer,"" was preaching in the desert country of Judea."
2715+"Matthew",3,2,"His message was simple and austere, like his desert surroundings: ""Change your life. God's kingdom is here."""
2716+"Matthew",3,3,"John and his message were authorized by Isaiah's prophecy: Thunder in the desert! Prepare for God's arrival! Make the road smooth and straight!"
2717+"Mark",1,1,"The good news of Jesus Christ - the Message! - begins here,"
2718+"Mark",1,2,"following to the letter the scroll of the prophet Isaiah. Watch closely: I'm sending my preacher ahead of you; He'll make the road smooth for you."
2719+"Mark",1,3,"Thunder in the desert! Prepare for God's arrival! Make the road smooth and straight!"
2720+"Luke",1,1,"So many others have tried their hand at putting together a story of the wonderful harvest of Scripture and history that took place among us,"
2721+"Luke",1,2,"using reports handed down by the original eyewitnesses who served this Word with their very lives."
2722+"Luke",1,3,"Since I have investigated all the reports in close detail, starting from the story's beginning, I decided to write it all out for you, most honorable Theophilus,"
2723+"John",1,1,"The Word was first, the Word present to God, God present to the Word. The Word was God,"
2724+"John",1,2,"in readiness for God from day one."
2725+"John",1,3,"Everything was created through him; nothing - not one thing! - came into being without him."
2726+"John",2,1,"Three days later there was a wedding in the village of Cana in Galilee. Jesus' mother was there."
2727+"John",2,2,"Jesus and his disciples were guests also."
2728+"John",2,3,"When they started running low on wine at the wedding banquet, Jesus' mother told him, ""They're just about out of wine."""
2729
2730=== modified file 'openlp/plugins/presentations/lib/pptviewlib/README.TXT'
2731--- openlp/plugins/presentations/lib/pptviewlib/README.TXT 2008-12-10 20:40:18 +0000
2732+++ openlp/plugins/presentations/lib/pptviewlib/README.TXT 2009-09-13 15:14:45 +0000
2733@@ -1,116 +1,116 @@
2734-
2735-PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
2736-Copyright (C) 2008 Jonathan Corwin (j@corwin.co.uk)
2737-
2738-This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program,
2739-allowing it to be more easily controlled from another program.
2740-
2741-The PowerPoint Viewer must already be installed on the destination machine, and is
2742-freely available at microsoft.com.
2743-
2744-The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing
2745-automation. This ability was removed from the 2003+ viewer offerings.
2746-
2747-To developers: I am not a C/C++ or Win32 API programmer as you can probably tell.
2748-The code and API of this DLL could certainly do with some tidying up, and the
2749-error trapping, where it exists, is very basic. I'll happily accept patches!
2750-
2751-This library is covered by the GPL (http://www.gnu.org/licenses/)
2752-It is NOT covered by the LGPL, so can only be used in GPL compatable programs.
2753-(http://www.gnu.org/licenses/why-not-lgpl.html)
2754-
2755-This README.TXT must be distributed with the pptviewlib.dll
2756-
2757-This library has a limit of 50 PowerPoints which can be opened simultaneously.
2758-
2759-USAGE
2760------
2761-int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
2762-
2763- Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly
2764- and creates preview images of each slide. Note PowerPoint Viewer only allows the
2765- slideshow to be resized whilst it is being loaded. It can be moved at any time however.
2766-
2767- The only way to count the number of slides is to step through the entire show. Therefore
2768- there will be a delay whilst opening large presentations for the first time.
2769- For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken.
2770-
2771- filename: The PowerPoint file to be opened. Full path
2772- hParentWnd: The window which will become the parent of the slideshow window.
2773- Can be NULL.
2774- rect: The location/dimensions of the slideshow window.
2775- If all properties of this structure are zero, the dimensions of the hParentWnd
2776- are used.
2777- previewpath If specified, the prefix to use for snapshot images of each slide, in the
2778- form: previewpath + n + ".bmp", where n is the slide number.
2779- A file called previewpath + "info.txt" will also be created containing information
2780- about the PPT file, to speed up future openings of the unmodified file.
2781- Note it is up the calling program to directly access these images if they
2782- are required.
2783-
2784- RETURNS: An unique identifier to pass to other methods in this library.
2785- If < 0, then the PPT failed to open.
2786- If >=0, ClosePPT must be called when the PPT is no longer being used
2787- or when the calling program is closed to release resources/hooks.
2788-
2789-void ClosePPT(int id);
2790- Closes the presentation, releasing any resources and hooks.
2791-
2792- id: The value returned from OpenPPT.
2793-
2794-int GetCurrentSlide(int id);
2795- Returns the current slide number (from 1)
2796-
2797- id: The value returned from OpenPPT.
2798-
2799-int GetSlideCount(int id);
2800- Returns the total number of slides.
2801-
2802- id: The value returned from OpenPPT.
2803-
2804-void NextStep(int id);
2805- Advances one step (animation) through the slideshow.
2806-
2807- id: The value returned from OpenPPT.
2808-
2809-void PrevStep(int id);
2810- Goes backwards one step (animation) through the slideshow.
2811-
2812- id: The value returned from OpenPPT.
2813-
2814-void GotoSlide(int id, int slideno);
2815- Goes directly to a specific slide in the slideshow
2816-
2817- id: The value returned from OpenPPT.
2818- slideno: The number of the slide (from 1) to go directly to.
2819-
2820- If the slide has already been displayed, then the completed slide with animations performed
2821- will be shown. This is how the PowerPoint Viewer works so have no control over this.
2822-
2823-void RestartShow(int id);
2824- Restarts the show from the beginning. To reset animations, behind the scenes it
2825- has to travel to the end and step backwards though the entire show. Therefore
2826- for large presentations there might be a delay.
2827-
2828- id: The value returned from OpenPPT.
2829-
2830-void Blank(int id);
2831- Blanks the screen, colour black.
2832-
2833- id: The value returned from OpenPPT.
2834-
2835-void Unblank(int id)
2836- Unblanks the screen, restoring it to it's pre-blank state.
2837-
2838- id: The value returned from OpenPPT.
2839-
2840-void Stop(int id)
2841- Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer)
2842-
2843- id: The value returned from OpenPPT.
2844-
2845-void Resume(int id)
2846- Moves the slideshow display back onto the screen following a Stop()
2847-
2848- id: The value returned from OpenPPT.
2849-
2850+
2851+PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
2852+Copyright (C) 2008 Jonathan Corwin (j@corwin.co.uk)
2853+
2854+This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program,
2855+allowing it to be more easily controlled from another program.
2856+
2857+The PowerPoint Viewer must already be installed on the destination machine, and is
2858+freely available at microsoft.com.
2859+
2860+The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing
2861+automation. This ability was removed from the 2003+ viewer offerings.
2862+
2863+To developers: I am not a C/C++ or Win32 API programmer as you can probably tell.
2864+The code and API of this DLL could certainly do with some tidying up, and the
2865+error trapping, where it exists, is very basic. I'll happily accept patches!
2866+
2867+This library is covered by the GPL (http://www.gnu.org/licenses/)
2868+It is NOT covered by the LGPL, so can only be used in GPL compatable programs.
2869+(http://www.gnu.org/licenses/why-not-lgpl.html)
2870+
2871+This README.TXT must be distributed with the pptviewlib.dll
2872+
2873+This library has a limit of 50 PowerPoints which can be opened simultaneously.
2874+
2875+USAGE
2876+-----
2877+int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
2878+
2879+ Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly
2880+ and creates preview images of each slide. Note PowerPoint Viewer only allows the
2881+ slideshow to be resized whilst it is being loaded. It can be moved at any time however.
2882+
2883+ The only way to count the number of slides is to step through the entire show. Therefore
2884+ there will be a delay whilst opening large presentations for the first time.
2885+ For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken.
2886+
2887+ filename: The PowerPoint file to be opened. Full path
2888+ hParentWnd: The window which will become the parent of the slideshow window.
2889+ Can be NULL.
2890+ rect: The location/dimensions of the slideshow window.
2891+ If all properties of this structure are zero, the dimensions of the hParentWnd
2892+ are used.
2893+ previewpath If specified, the prefix to use for snapshot images of each slide, in the
2894+ form: previewpath + n + ".bmp", where n is the slide number.
2895+ A file called previewpath + "info.txt" will also be created containing information
2896+ about the PPT file, to speed up future openings of the unmodified file.
2897+ Note it is up the calling program to directly access these images if they
2898+ are required.
2899+
2900+ RETURNS: An unique identifier to pass to other methods in this library.
2901+ If < 0, then the PPT failed to open.
2902+ If >=0, ClosePPT must be called when the PPT is no longer being used
2903+ or when the calling program is closed to release resources/hooks.
2904+
2905+void ClosePPT(int id);
2906+ Closes the presentation, releasing any resources and hooks.
2907+
2908+ id: The value returned from OpenPPT.
2909+
2910+int GetCurrentSlide(int id);
2911+ Returns the current slide number (from 1)
2912+
2913+ id: The value returned from OpenPPT.
2914+
2915+int GetSlideCount(int id);
2916+ Returns the total number of slides.
2917+
2918+ id: The value returned from OpenPPT.
2919+
2920+void NextStep(int id);
2921+ Advances one step (animation) through the slideshow.
2922+
2923+ id: The value returned from OpenPPT.
2924+
2925+void PrevStep(int id);
2926+ Goes backwards one step (animation) through the slideshow.
2927+
2928+ id: The value returned from OpenPPT.
2929+
2930+void GotoSlide(int id, int slideno);
2931+ Goes directly to a specific slide in the slideshow
2932+
2933+ id: The value returned from OpenPPT.
2934+ slideno: The number of the slide (from 1) to go directly to.
2935+
2936+ If the slide has already been displayed, then the completed slide with animations performed
2937+ will be shown. This is how the PowerPoint Viewer works so have no control over this.
2938+
2939+void RestartShow(int id);
2940+ Restarts the show from the beginning. To reset animations, behind the scenes it
2941+ has to travel to the end and step backwards though the entire show. Therefore
2942+ for large presentations there might be a delay.
2943+
2944+ id: The value returned from OpenPPT.
2945+
2946+void Blank(int id);
2947+ Blanks the screen, colour black.
2948+
2949+ id: The value returned from OpenPPT.
2950+
2951+void Unblank(int id)
2952+ Unblanks the screen, restoring it to it's pre-blank state.
2953+
2954+ id: The value returned from OpenPPT.
2955+
2956+void Stop(int id)
2957+ Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer)
2958+
2959+ id: The value returned from OpenPPT.
2960+
2961+void Resume(int id)
2962+ Moves the slideshow display back onto the screen following a Stop()
2963+
2964+ id: The value returned from OpenPPT.
2965+
2966
2967=== modified file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp'
2968--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp 2008-12-10 20:40:18 +0000
2969+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp 2009-09-13 15:14:45 +0000
2970@@ -1,753 +1,753 @@
2971-/*
2972- * PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
2973- * Copyright (C) 2008 Jonathan Corwin
2974- *
2975- * This program is free software: you can redistribute it and/or modify
2976- * it under the terms of the GNU General Public License as published by
2977- * the Free Software Foundation, either version 2 of the License, or
2978- * (at your option) any later version.
2979- *
2980- * This program is distributed in the hope that it will be useful,
2981- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2982- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2983- * GNU General Public License for more details.
2984- *
2985- * You should have received a copy of the GNU General Public License
2986- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2987- */
2988-
2989-
2990-#define WIN32_LEAN_AND_MEAN
2991-#include <windows.h>
2992-#include <string.h>
2993-#include <stdlib.h>
2994-#include <stdio.h>
2995-#include <time.h>
2996-#include <sys/types.h>
2997-#include <sys/stat.h>
2998-#include "pptviewlib.h"
2999-
3000-// Because of the callbacks used by SetWindowsHookEx, the memory used needs to be
3001-// sharable across processes (the callbacks are done from a different process)
3002-// Therefore use data_seg with RWS memory.
3003-//
3004-// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for alternative
3005-// method of holding memory, removing fixed limits which would allow dynamic number
3006-// of items, rather than a fixed number. Use a Local\ mapping, since global has UAC
3007-// issues in Vista.
3008-#pragma data_seg(".PPTVIEWLIB")
3009-PPTVIEWOBJ pptviewobj[MAX_PPTOBJS] = {NULL};
3010-HHOOK globalhook = NULL;
3011-BOOL debug = FALSE;
3012-#pragma data_seg()
3013-#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
3014-
3015-#define DEBUG(...) if(debug) printf(__VA_ARGS__)
3016-
3017-
3018-HINSTANCE hInstance = NULL;
3019-
3020-BOOL APIENTRY DllMain( HMODULE hModule,
3021- DWORD ul_reason_for_call,
3022- LPVOID lpReserved
3023- )
3024-{
3025- hInstance = (HINSTANCE)hModule;
3026- switch (ul_reason_for_call)
3027- {
3028- case DLL_PROCESS_ATTACH:
3029- DEBUG("PROCESS_ATTACH\n");
3030- break;
3031- case DLL_THREAD_ATTACH:
3032- DEBUG("THREAD_ATTACH\n");
3033- break;
3034- case DLL_THREAD_DETACH:
3035- DEBUG("THREAD_DETACH\n");
3036- break;
3037- case DLL_PROCESS_DETACH:
3038- // Clean up... hopefully there is only the one process attached?
3039- // We'll find out soon enough during tests!
3040- DEBUG("PROCESS_DETACH\n");
3041- for(int i = 0; i<MAX_PPTOBJS; i++)
3042- ClosePPT(i);
3043- break;
3044- }
3045- return TRUE;
3046-}
3047-DllExport void SetDebug(BOOL onoff)
3048-{
3049- printf("SetDebug\n");
3050- debug = onoff;
3051- DEBUG("enabled\n");
3052-}
3053-
3054-// Open the PointPoint, count the slides and take a snapshot of each slide
3055-// for use in previews
3056-// previewpath is a prefix for the location to put preview images of each slide.
3057-// "<n>.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would
3058-// create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc.
3059-// It will also create a *info.txt containing information about the ppt
3060-DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath)
3061-{
3062- STARTUPINFO si;
3063- PROCESS_INFORMATION pi;
3064- char cmdline[MAX_PATH * 2];
3065- int id;
3066-
3067- DEBUG("OpenPPT start: %s; %s\n", filename, previewpath);
3068- DEBUG("OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top, rect.left, rect.bottom, rect.right);
3069- if(GetPPTViewerPath(cmdline, sizeof(cmdline))==FALSE)
3070- {
3071- DEBUG("OpenPPT: GetPPTViewerPath failed\n");
3072- return -1;
3073- }
3074- id = -1;
3075- for(int i = 0; i<MAX_PPTOBJS; i++)
3076- {
3077- if(pptviewobj[i].state==PPT_CLOSED)
3078- {
3079- id=i;
3080- break;
3081- }
3082- }
3083- if(id<0)
3084- {
3085- DEBUG("OpenPPT: Too many PPTs\n");
3086- return -1;
3087- }
3088- memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ));
3089- strcpy_s(pptviewobj[id].filename, MAX_PATH, filename);
3090- strcpy_s(pptviewobj[id].previewpath, MAX_PATH, previewpath);
3091- pptviewobj[id].state = PPT_CLOSED;
3092- pptviewobj[id].slideCount = 0;
3093- pptviewobj[id].currentSlide = 0;
3094- pptviewobj[id].firstSlideSteps = 0;
3095- pptviewobj[id].hParentWnd = hParentWnd;
3096- pptviewobj[id].hWnd = NULL;
3097- pptviewobj[id].hWnd2 = NULL;
3098- if(hParentWnd!=NULL&&rect.top==0&&rect.bottom==0&&rect.left==0&&rect.right==0)
3099- {
3100- LPRECT wndrect = NULL;
3101- GetWindowRect(hParentWnd, wndrect);
3102- pptviewobj[id].rect.top = 0;
3103- pptviewobj[id].rect.left = 0;
3104- pptviewobj[id].rect.bottom = wndrect->bottom-wndrect->top;
3105- pptviewobj[id].rect.right = wndrect->right-wndrect->left;
3106- }
3107- else
3108- {
3109- pptviewobj[id].rect.top = rect.top;
3110- pptviewobj[id].rect.left = rect.left;
3111- pptviewobj[id].rect.bottom = rect.bottom;
3112- pptviewobj[id].rect.right = rect.right;
3113- }
3114- strcat_s(cmdline, MAX_PATH * 2, "/S \"");
3115- strcat_s(cmdline, MAX_PATH * 2, filename);
3116- strcat_s(cmdline, MAX_PATH * 2, "\"");
3117- memset(&si, 0, sizeof(si));
3118- memset(&pi, 0, sizeof(pi));
3119- BOOL gotinfo = GetPPTInfo(id);
3120- /*
3121- * I'd really like to just hook on the new threadid. However this always gives
3122- * error 87. Perhaps I'm hooking to soon? No idea... however can't wait
3123- * since I need to ensure I pick up the WM_CREATE as this is the only
3124- * time the window can be resized in such away the content scales correctly
3125- *
3126- * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId);
3127- */
3128- if(globalhook!=NULL)
3129- UnhookWindowsHookEx(globalhook);
3130- globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
3131- if(globalhook==0)
3132- {
3133- DEBUG("OpenPPT: SetWindowsHookEx failed\n");
3134- ClosePPT(id);
3135- return -1;
3136- }
3137- pptviewobj[id].state = PPT_STARTED;
3138- Sleep(10);
3139- if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
3140- {
3141- DEBUG("OpenPPT: CreateProcess failed\n");
3142- ClosePPT(id);
3143- return -1;
3144- }
3145- pptviewobj[id].dwProcessId = pi.dwProcessId;
3146- pptviewobj[id].dwThreadId = pi.dwThreadId;
3147- pptviewobj[id].hThread = pi.hThread;
3148- pptviewobj[id].hProcess = pi.hProcess;
3149- while(pptviewobj[id].state==PPT_STARTED)
3150- Sleep(10);
3151- if(gotinfo)
3152- {
3153- DEBUG("OpenPPT: Info loaded, no refresh\n");
3154- pptviewobj[id].state = PPT_LOADED;
3155- Resume(id);
3156- }
3157- else
3158- {
3159- DEBUG("OpenPPT: Get info\n");
3160- pptviewobj[id].steps = 0;
3161- int steps = 0;
3162- while(pptviewobj[id].state==PPT_OPENED)
3163- {
3164- if(steps<=pptviewobj[id].steps)
3165- {
3166- Sleep(20);
3167- DEBUG("OpenPPT: Step %d/%d\n",steps,pptviewobj[id].steps);
3168- steps++;
3169- NextStep(id);
3170- }
3171- Sleep(10);
3172- }
3173- DEBUG("OpenPPT: Steps %d, first slide steps %d\n",pptviewobj[id].steps,pptviewobj[id].firstSlideSteps);
3174- SavePPTInfo(id);
3175- if(pptviewobj[id].state==PPT_CLOSING){
3176- ClosePPT(id);
3177- id=-1;
3178- }
3179- else
3180- RestartShow(id);
3181- }
3182- if(id>=0)
3183- {
3184- if(pptviewobj[id].mhook!=NULL)
3185- UnhookWindowsHookEx(pptviewobj[id].mhook);
3186- pptviewobj[id].mhook = NULL;
3187- }
3188- DEBUG("OpenPPT: Exit: id=%i\n", id);
3189- return id;
3190-}
3191-// Load information about the ppt from an info.txt file.
3192-// Format:
3193-// version
3194-// filedate
3195-// filesize
3196-// slidecount
3197-// first slide steps
3198-BOOL GetPPTInfo(int id)
3199-{
3200- struct _stat filestats;
3201- char info[MAX_PATH];
3202- FILE* pFile;
3203- char buf[100];
3204-
3205- DEBUG("GetPPTInfo: start\n");
3206- if(_stat(pptviewobj[id].filename, &filestats)!=0)
3207- return FALSE;
3208- sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
3209- int err = fopen_s(&pFile, info, "r");
3210- if(err!=0)
3211- {
3212- DEBUG("GetPPTInfo: file open failed - %d\n", err);
3213- return FALSE;
3214- }
3215- fgets(buf, 100, pFile); // version == 1
3216- fgets(buf, 100, pFile);
3217- if(filestats.st_mtime!=atoi(buf))
3218- {
3219- fclose (pFile);
3220- return FALSE;
3221- }
3222- fgets(buf, 100, pFile);
3223- if(filestats.st_size!=atoi(buf))
3224- {
3225- fclose (pFile);
3226- return FALSE;
3227- }
3228- fgets(buf, 100, pFile); // slidecount
3229- int slidecount = atoi(buf);
3230- fgets(buf, 100, pFile); // first slide steps
3231- int firstslidesteps = atoi(buf);
3232- // check all the preview images still exist
3233- for(int i = 1; i<=slidecount; i++)
3234- {
3235- sprintf_s(info, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, i);
3236- if(GetFileAttributes(info)==INVALID_FILE_ATTRIBUTES)
3237- return FALSE;
3238- }
3239- fclose(pFile);
3240- pptviewobj[id].slideCount = slidecount;
3241- pptviewobj[id].firstSlideSteps = firstslidesteps;
3242- DEBUG("GetPPTInfo: exit ok\n");
3243- return TRUE;
3244-}
3245-
3246-BOOL SavePPTInfo(int id)
3247-{
3248- struct _stat filestats;
3249- char info[MAX_PATH];
3250- FILE* pFile;
3251-
3252- DEBUG("SavePPTInfo: start\n");
3253- if(_stat(pptviewobj[id].filename, &filestats)!=0)
3254- {
3255- DEBUG("SavePPTInfo: stat of %s failed\n", pptviewobj[id].filename);
3256- return FALSE;
3257- }
3258- sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
3259- int err = fopen_s(&pFile, info, "w");
3260- if(err!=0)
3261- {
3262- DEBUG("SavePPTInfo: fopen of %s failed%i\n", info, err);
3263- return FALSE;
3264- }
3265- fprintf(pFile, "1\n");
3266- fprintf(pFile, "%u\n", filestats.st_mtime);
3267- fprintf(pFile, "%u\n", filestats.st_size);
3268- fprintf(pFile, "%u\n", pptviewobj[id].slideCount);
3269- fprintf(pFile, "%u\n", pptviewobj[id].firstSlideSteps);
3270- fclose (pFile);
3271- DEBUG("SavePPTInfo: exit ok\n");
3272- return TRUE;
3273-}
3274-
3275-// Get the path of the PowerPoint viewer from the registry
3276-BOOL GetPPTViewerPath(char *pptviewerpath, int strsize)
3277-{
3278- HKEY hkey;
3279- DWORD dwtype, dwsize;
3280- LRESULT lresult;
3281-
3282- DEBUG("GetPPTViewerPath: start\n");
3283- if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
3284- if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
3285- return FALSE;
3286- dwtype = REG_SZ;
3287- dwsize = (DWORD)strsize;
3288- lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pptviewerpath, &dwsize );
3289- RegCloseKey(hkey);
3290- if(lresult!=ERROR_SUCCESS)
3291- return FALSE;
3292- pptviewerpath[strlen(pptviewerpath)-4] = '\0'; // remove "%1" from end of key value
3293- DEBUG("GetPPTViewerPath: exit ok\n");
3294- return TRUE;
3295-}
3296-
3297-// Unhook the Windows hook
3298-void Unhook(int id)
3299-{
3300- DEBUG("Unhook: start %d\n", id);
3301- if(pptviewobj[id].hook!=NULL)
3302- UnhookWindowsHookEx(pptviewobj[id].hook);
3303- if(pptviewobj[id].mhook!=NULL)
3304- UnhookWindowsHookEx(pptviewobj[id].mhook);
3305- pptviewobj[id].hook = NULL;
3306- pptviewobj[id].mhook = NULL;
3307- DEBUG("Unhook: exit ok\n");
3308-}
3309-
3310-// Close the PowerPoint viewer, release resources
3311-DllExport void ClosePPT(int id)
3312-{
3313- DEBUG("ClosePPT: start%d\n", id);
3314- pptviewobj[id].state = PPT_CLOSED;
3315- Unhook(id);
3316- if(pptviewobj[id].hWnd==0)
3317- TerminateThread(pptviewobj[id].hThread, 0);
3318- else
3319- PostMessage(pptviewobj[id].hWnd, WM_CLOSE, 0, 0);
3320- CloseHandle(pptviewobj[id].hThread);
3321- CloseHandle(pptviewobj[id].hProcess);
3322- memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ));
3323- DEBUG("ClosePPT: exit ok\n");
3324- return;
3325-}
3326-// Moves the show back onto the display
3327-DllExport void Resume(int id)
3328-{
3329- DEBUG("Resume: %d\n", id);
3330- MoveWindow(pptviewobj[id].hWnd, pptviewobj[id].rect.left, pptviewobj[id].rect.top,
3331- pptviewobj[id].rect.right - pptviewobj[id].rect.left,
3332- pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
3333- Unblank(id);
3334-}
3335-// Moves the show off the screen so it can't be seen
3336-DllExport void Stop(int id)
3337-{
3338- DEBUG("Stop:%d\n", id);
3339- MoveWindow(pptviewobj[id].hWnd, -32000, -32000,
3340- pptviewobj[id].rect.right - pptviewobj[id].rect.left,
3341- pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
3342-}
3343-
3344-// Return the total number of slides
3345-DllExport int GetSlideCount(int id)
3346-{
3347- DEBUG("GetSlideCount:%d\n", id);
3348- if(pptviewobj[id].state==0)
3349- return -1;
3350- else
3351- return pptviewobj[id].slideCount;
3352-}
3353-
3354-// Return the number of the slide currently viewing
3355-DllExport int GetCurrentSlide(int id)
3356-{
3357- DEBUG("GetCurrentSlide:%d\n", id);
3358- if(pptviewobj[id].state==0)
3359- return -1;
3360- else
3361- return pptviewobj[id].currentSlide;
3362-}
3363-
3364-// Take a step forwards through the show
3365-DllExport void NextStep(int id)
3366-{
3367- DEBUG("NextStep:%d\n", id);
3368- if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
3369- return;
3370- PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
3371-}
3372-
3373-// Take a step backwards through the show
3374-DllExport void PrevStep(int id)
3375-{
3376- DEBUG("PrevStep:%d\n", id);
3377- PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
3378-}
3379-
3380-// Blank the show (black screen)
3381-DllExport void Blank(int id)
3382-{
3383- // B just toggles blank on/off. However pressing any key unblanks.
3384- // So send random unmapped letter first (say 'A'), then we can
3385- // better guarantee B will blank instead of trying to guess
3386- // whether it was already blank or not.
3387- DEBUG("Blank:%d\n", id);
3388- HWND h1 = GetForegroundWindow();
3389- HWND h2 = GetFocus();
3390- SetForegroundWindow(pptviewobj[id].hWnd);
3391- SetFocus(pptviewobj[id].hWnd);
3392- Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
3393- keybd_event((int)'A', 0, 0, 0);
3394- keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0);
3395- keybd_event((int)'B', 0, 0, 0);
3396- keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0);
3397- SetForegroundWindow(h1);
3398- SetFocus(h2);
3399- //PostMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'B', 0x00300001);
3400- //PostMessage(pptviewobj[id].hWnd2, WM_CHAR, 'b', 0x00300001);
3401- //PostMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'B', 0xC0300001);
3402-}
3403-// Unblank the show
3404-DllExport void Unblank(int id)
3405-{
3406- DEBUG("Unblank:%d\n", id);
3407- // Pressing any key resumes.
3408- // For some reason SendMessage works for unblanking, but not blanking.
3409-// SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'A', 0);
3410- SendMessage(pptviewobj[id].hWnd2, WM_CHAR, 'A', 0);
3411-// SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'A', 0);
3412-// HWND h1 = GetForegroundWindow();
3413-// HWND h2 = GetFocus();
3414-// Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
3415-// SetForegroundWindow(pptviewobj[id].hWnd);
3416-// SetFocus(pptviewobj[id].hWnd);
3417-// keybd_event((int)'A', 0, 0, 0);
3418-// SetForegroundWindow(h1);
3419-// SetFocus(h2);
3420-}
3421-
3422-// Go directly to a slide
3423-DllExport void GotoSlide(int id, int slideno)
3424-{
3425- DEBUG("GotoSlide %i %i:\n", id, slideno);
3426- // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work
3427- // perhaps I was sending to the wrong window? No idea.
3428- // Anyway fall back to keybd_event, which is OK as long we makesure
3429- // the slideshow has focus first
3430- char ch[10];
3431-
3432- if(slideno<0) return;
3433- _itoa_s(slideno, ch, 10, 10);
3434- HWND h1 = GetForegroundWindow();
3435- HWND h2 = GetFocus();
3436- SetForegroundWindow(pptviewobj[id].hWnd);
3437- SetFocus(pptviewobj[id].hWnd);
3438- Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
3439- for(int i=0;i<10;i++)
3440- {
3441- if(ch[i]=='\0') break;
3442- keybd_event((BYTE)ch[i], 0, 0, 0);
3443- keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0);
3444- }
3445- keybd_event(VK_RETURN, 0, 0, 0);
3446- keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
3447- SetForegroundWindow(h1);
3448- SetFocus(h2);
3449-
3450- //for(int i=0;i<10;i++)
3451- //{
3452- // if(ch[i]=='\0') break;
3453- // SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, ch[i], 0);
3454- // SendMessage(pptviewobj[id].hWnd2, WM_CHAR, ch[i], 0);
3455- // SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, ch[i], 0);
3456- //}
3457- //SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, VK_RETURN, 0);
3458- //SendMessage(pptviewobj[id].hWnd2, WM_CHAR, VK_RETURN, 0);
3459- //SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, VK_RETURN, 0);
3460- //keybd_event(VK_RETURN, 0, 0, 0);
3461-}
3462-
3463-// Restart the show from the beginning
3464-DllExport void RestartShow(int id)
3465-{
3466- // If we just go direct to slide one, then it remembers that all other slides have
3467- // been animated, so ends up just showing the completed slides of those slides that
3468- // have been animated next time we advance.
3469- // Only way I've found to get around this is to step backwards all the way through.
3470- // Lets move the window out of the way first so the audience doesn't see this.
3471- DEBUG("RestartShow:%d\n", id);
3472- Stop(id);
3473- GotoSlide(id, pptviewobj[id].slideCount);
3474- while(pptviewobj[id].currentSlide>1)
3475- {
3476- PrevStep(id);
3477- Sleep(10);
3478- }
3479- for(int i=0;i<=pptviewobj[id].firstSlideSteps;i++)
3480- {
3481- PrevStep(id);
3482- Sleep(10);
3483- }
3484- Resume(id);
3485-}
3486-
3487-// This hook is started with the PPTVIEW.EXE process and waits for the
3488-// WM_CREATEWND message. At this point (and only this point) can the
3489-// window be resized to the correct size.
3490-// Release the hook as soon as we're complete to free up resources
3491-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
3492-{
3493- HHOOK hook = globalhook;
3494- if(nCode==HCBT_CREATEWND)
3495- {
3496- char csClassName[16];
3497- HWND hCurrWnd = (HWND)wParam;
3498- DWORD retProcId = NULL;
3499- GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
3500- if((strcmp(csClassName, "paneClassDC")==0)
3501- ||(strcmp(csClassName, "screenClass")==0))
3502- {
3503- int id=-1;
3504- DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
3505- for(int i=0; i<MAX_PPTOBJS; i++)
3506- {
3507- if(pptviewobj[i].dwThreadId==windowthread)
3508- {
3509- id=i;
3510- break;
3511- }
3512- }
3513- if(id>=0)
3514- {
3515- if(strcmp(csClassName, "paneClassDC")==0)
3516- pptviewobj[id].hWnd2=hCurrWnd;
3517- else
3518- {
3519- pptviewobj[id].hWnd=hCurrWnd;
3520- CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
3521- if(pptviewobj[id].hParentWnd!=NULL)
3522- cw->lpcs->hwndParent = pptviewobj[id].hParentWnd;
3523- cw->lpcs->cy=(pptviewobj[id].rect.bottom-pptviewobj[id].rect.top);
3524- cw->lpcs->cx=(pptviewobj[id].rect.right-pptviewobj[id].rect.left);
3525- cw->lpcs->y=-32000;
3526- cw->lpcs->x=-32000;
3527- }
3528- if((pptviewobj[id].hWnd!=NULL)&&(pptviewobj[id].hWnd2!=NULL))
3529- {
3530- UnhookWindowsHookEx(globalhook);
3531- globalhook=NULL;
3532- pptviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pptviewobj[id].dwThreadId);
3533- pptviewobj[id].mhook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInstance,pptviewobj[id].dwThreadId);
3534- Sleep(10);
3535- pptviewobj[id].state = PPT_OPENED;
3536- }
3537- }
3538- }
3539- }
3540- return CallNextHookEx(hook,nCode,wParam,lParam);
3541-}
3542-
3543-// This hook exists whilst the slideshow is loading but only listens on the
3544-// slideshows thread. It listens out for mousewheel events
3545-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
3546-{
3547- HHOOK hook = NULL;
3548- MSG *pMSG = (MSG *)lParam;
3549- DWORD windowthread = GetWindowThreadProcessId(pMSG->hwnd,NULL);
3550- int id=-1;
3551- for(int i=0; i<MAX_PPTOBJS; i++)
3552- {
3553- if(pptviewobj[i].dwThreadId==windowthread)
3554- {
3555- id=i;
3556- hook = pptviewobj[id].mhook;
3557- break;
3558- }
3559- }
3560- if(id>=0&&nCode==HC_ACTION&&wParam==PM_REMOVE&&pMSG->message==WM_MOUSEWHEEL)
3561- {
3562- if(pptviewobj[id].state!=PPT_LOADED)
3563- {
3564- if(pptviewobj[id].currentSlide==1)
3565- pptviewobj[id].firstSlideSteps++;
3566- pptviewobj[id].steps++;
3567- }
3568- }
3569- return CallNextHookEx(hook, nCode, wParam, lParam);
3570-}
3571-// This hook exists whilst the slideshow is running but only listens on the
3572-// slideshows thread. It listens out for slide changes, message WM_USER+22.
3573-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
3574- CWPSTRUCT *cwp;
3575- cwp = (CWPSTRUCT *)lParam;
3576- HHOOK hook = NULL;
3577- char filename[MAX_PATH];
3578-
3579- DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
3580- int id=-1;
3581- for(int i=0; i<MAX_PPTOBJS; i++)
3582- {
3583- if(pptviewobj[i].dwThreadId==windowthread)
3584- {
3585- id=i;
3586- hook = pptviewobj[id].hook;
3587- break;
3588- }
3589- }
3590- if((id>=0)&&(nCode==HC_ACTION))
3591- {
3592- if(cwp->message==WM_USER+22)
3593- {
3594- if(pptviewobj[id].state != PPT_LOADED)
3595- {
3596- if((pptviewobj[id].currentSlide>0)
3597- && (pptviewobj[id].previewpath!=NULL&&strlen(pptviewobj[id].previewpath)>0))
3598- {
3599- sprintf_s(filename, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, pptviewobj[id].currentSlide);
3600- CaptureAndSaveWindow(cwp->hwnd, filename);
3601- }
3602- }
3603- if(cwp->wParam==0)
3604- {
3605- if(pptviewobj[id].currentSlide>0)
3606- {
3607- pptviewobj[id].state = PPT_LOADED;
3608- pptviewobj[id].currentSlide = pptviewobj[id].slideCount+1;
3609- }
3610- }
3611- else
3612- {
3613- pptviewobj[id].currentSlide = cwp->wParam - 255;
3614- if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
3615- pptviewobj[id].slideCount = pptviewobj[id].currentSlide;
3616- }
3617- }
3618- if((pptviewobj[id].state != PPT_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT))
3619- pptviewobj[id].state = PPT_CLOSING;
3620- }
3621- return CallNextHookEx(hook,nCode,wParam,lParam);
3622-}
3623-
3624-VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename)
3625-{
3626- HBITMAP hBmp;
3627- if ((hBmp = CaptureWindow(hWnd)) == NULL)
3628- return;
3629-
3630- RECT client;
3631- GetClientRect (hWnd, &client);
3632- UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits
3633- UINT uiRemainderForPadding;
3634-
3635- if ((uiRemainderForPadding = uiBytesPerRow % sizeof (DWORD)) > 0)
3636- uiBytesPerRow += (sizeof (DWORD) - uiRemainderForPadding);
3637-
3638- UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom;
3639- PBYTE pDataBits;
3640-
3641- if ((pDataBits = new BYTE [uiBytesPerAllRows]) != NULL)
3642- {
3643- BITMAPINFOHEADER bmi = {0};
3644- BITMAPFILEHEADER bmf = {0};
3645-
3646- // Prepare to get the data out of HBITMAP:
3647- bmi.biSize = sizeof (bmi);
3648- bmi.biPlanes = 1;
3649- bmi.biBitCount = 24;
3650- bmi.biHeight = client.bottom;
3651- bmi.biWidth = client.right;
3652-
3653- // Get it:
3654- HDC hDC = GetDC (hWnd);
3655- GetDIBits (hDC, hBmp, 0, client.bottom, pDataBits,
3656- (BITMAPINFO*) &bmi, DIB_RGB_COLORS);
3657- ReleaseDC (hWnd, hDC);
3658-
3659- // Fill the file header:
3660- bmf.bfOffBits = sizeof (bmf) + sizeof (bmi);
3661- bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows;
3662- bmf.bfType = 0x4D42;
3663-
3664- // Writing:
3665- FILE* pFile;
3666- int err = fopen_s(&pFile, filename, "wb");
3667- if (err == 0)
3668- {
3669- fwrite (&bmf, sizeof (bmf), 1, pFile);
3670- fwrite (&bmi, sizeof (bmi), 1, pFile);
3671- fwrite (pDataBits, sizeof (BYTE), uiBytesPerAllRows, pFile);
3672- fclose (pFile);
3673- }
3674- delete [] pDataBits;
3675- }
3676- DeleteObject (hBmp);
3677-}
3678-HBITMAP CaptureWindow (HWND hWnd) {
3679- HDC hDC;
3680- BOOL bOk = FALSE;
3681- HBITMAP hImage = NULL;
3682-
3683- hDC = GetDC (hWnd);
3684- RECT rcClient;
3685- GetClientRect (hWnd, &rcClient);
3686- if ((hImage = CreateCompatibleBitmap (hDC, rcClient.right, rcClient.bottom)) != NULL)
3687- {
3688- HDC hMemDC;
3689- HBITMAP hDCBmp;
3690-
3691- if ((hMemDC = CreateCompatibleDC (hDC)) != NULL)
3692- {
3693- hDCBmp = (HBITMAP) SelectObject (hMemDC, hImage);
3694- HMODULE hLib = LoadLibrary("User32");
3695- // PrintWindow works for windows outside displayable area
3696- // but was only introduced in WinXP. BitBlt requires the window to be topmost
3697- // and within the viewable area of the display
3698- if(GetProcAddress(hLib, "PrintWindow")==NULL)
3699- {
3700- SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
3701- BitBlt (hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0, 0, SRCCOPY);
3702- SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0, SWP_NOSIZE);
3703- }
3704- else
3705- {
3706- PrintWindow(hWnd, hMemDC, 0);
3707- }
3708- SelectObject (hMemDC, hDCBmp);
3709- DeleteDC (hMemDC);
3710- bOk = TRUE;
3711- }
3712- }
3713- ReleaseDC (hWnd, hDC);
3714- if (! bOk)
3715- {
3716- if (hImage)
3717- {
3718- DeleteObject (hImage);
3719- hImage = NULL;
3720- }
3721- }
3722- return hImage;
3723-}
3724+/*
3725+ * PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
3726+ * Copyright (C) 2008 Jonathan Corwin
3727+ *
3728+ * This program is free software: you can redistribute it and/or modify
3729+ * it under the terms of the GNU General Public License as published by
3730+ * the Free Software Foundation, either version 2 of the License, or
3731+ * (at your option) any later version.
3732+ *
3733+ * This program is distributed in the hope that it will be useful,
3734+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3735+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3736+ * GNU General Public License for more details.
3737+ *
3738+ * You should have received a copy of the GNU General Public License
3739+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3740+ */
3741+
3742+
3743+#define WIN32_LEAN_AND_MEAN
3744+#include <windows.h>
3745+#include <string.h>
3746+#include <stdlib.h>
3747+#include <stdio.h>
3748+#include <time.h>
3749+#include <sys/types.h>
3750+#include <sys/stat.h>
3751+#include "pptviewlib.h"
3752+
3753+// Because of the callbacks used by SetWindowsHookEx, the memory used needs to be
3754+// sharable across processes (the callbacks are done from a different process)
3755+// Therefore use data_seg with RWS memory.
3756+//
3757+// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for alternative
3758+// method of holding memory, removing fixed limits which would allow dynamic number
3759+// of items, rather than a fixed number. Use a Local\ mapping, since global has UAC
3760+// issues in Vista.
3761+#pragma data_seg(".PPTVIEWLIB")
3762+PPTVIEWOBJ pptviewobj[MAX_PPTOBJS] = {NULL};
3763+HHOOK globalhook = NULL;
3764+BOOL debug = FALSE;
3765+#pragma data_seg()
3766+#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
3767+
3768+#define DEBUG(...) if(debug) printf(__VA_ARGS__)
3769+
3770+
3771+HINSTANCE hInstance = NULL;
3772+
3773+BOOL APIENTRY DllMain( HMODULE hModule,
3774+ DWORD ul_reason_for_call,
3775+ LPVOID lpReserved
3776+ )
3777+{
3778+ hInstance = (HINSTANCE)hModule;
3779+ switch (ul_reason_for_call)
3780+ {
3781+ case DLL_PROCESS_ATTACH:
3782+ DEBUG("PROCESS_ATTACH\n");
3783+ break;
3784+ case DLL_THREAD_ATTACH:
3785+ DEBUG("THREAD_ATTACH\n");
3786+ break;
3787+ case DLL_THREAD_DETACH:
3788+ DEBUG("THREAD_DETACH\n");
3789+ break;
3790+ case DLL_PROCESS_DETACH:
3791+ // Clean up... hopefully there is only the one process attached?
3792+ // We'll find out soon enough during tests!
3793+ DEBUG("PROCESS_DETACH\n");
3794+ for(int i = 0; i<MAX_PPTOBJS; i++)
3795+ ClosePPT(i);
3796+ break;
3797+ }
3798+ return TRUE;
3799+}
3800+DllExport void SetDebug(BOOL onoff)
3801+{
3802+ printf("SetDebug\n");
3803+ debug = onoff;
3804+ DEBUG("enabled\n");
3805+}
3806+
3807+// Open the PointPoint, count the slides and take a snapshot of each slide
3808+// for use in previews
3809+// previewpath is a prefix for the location to put preview images of each slide.
3810+// "<n>.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would
3811+// create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc.
3812+// It will also create a *info.txt containing information about the ppt
3813+DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath)
3814+{
3815+ STARTUPINFO si;
3816+ PROCESS_INFORMATION pi;
3817+ char cmdline[MAX_PATH * 2];
3818+ int id;
3819+
3820+ DEBUG("OpenPPT start: %s; %s\n", filename, previewpath);
3821+ DEBUG("OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top, rect.left, rect.bottom, rect.right);
3822+ if(GetPPTViewerPath(cmdline, sizeof(cmdline))==FALSE)
3823+ {
3824+ DEBUG("OpenPPT: GetPPTViewerPath failed\n");
3825+ return -1;
3826+ }
3827+ id = -1;
3828+ for(int i = 0; i<MAX_PPTOBJS; i++)
3829+ {
3830+ if(pptviewobj[i].state==PPT_CLOSED)
3831+ {
3832+ id=i;
3833+ break;
3834+ }
3835+ }
3836+ if(id<0)
3837+ {
3838+ DEBUG("OpenPPT: Too many PPTs\n");
3839+ return -1;
3840+ }
3841+ memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ));
3842+ strcpy_s(pptviewobj[id].filename, MAX_PATH, filename);
3843+ strcpy_s(pptviewobj[id].previewpath, MAX_PATH, previewpath);
3844+ pptviewobj[id].state = PPT_CLOSED;
3845+ pptviewobj[id].slideCount = 0;
3846+ pptviewobj[id].currentSlide = 0;
3847+ pptviewobj[id].firstSlideSteps = 0;
3848+ pptviewobj[id].hParentWnd = hParentWnd;
3849+ pptviewobj[id].hWnd = NULL;
3850+ pptviewobj[id].hWnd2 = NULL;
3851+ if(hParentWnd!=NULL&&rect.top==0&&rect.bottom==0&&rect.left==0&&rect.right==0)
3852+ {
3853+ LPRECT wndrect = NULL;
3854+ GetWindowRect(hParentWnd, wndrect);
3855+ pptviewobj[id].rect.top = 0;
3856+ pptviewobj[id].rect.left = 0;
3857+ pptviewobj[id].rect.bottom = wndrect->bottom-wndrect->top;
3858+ pptviewobj[id].rect.right = wndrect->right-wndrect->left;
3859+ }
3860+ else
3861+ {
3862+ pptviewobj[id].rect.top = rect.top;
3863+ pptviewobj[id].rect.left = rect.left;
3864+ pptviewobj[id].rect.bottom = rect.bottom;
3865+ pptviewobj[id].rect.right = rect.right;
3866+ }
3867+ strcat_s(cmdline, MAX_PATH * 2, "/S \"");
3868+ strcat_s(cmdline, MAX_PATH * 2, filename);
3869+ strcat_s(cmdline, MAX_PATH * 2, "\"");
3870+ memset(&si, 0, sizeof(si));
3871+ memset(&pi, 0, sizeof(pi));
3872+ BOOL gotinfo = GetPPTInfo(id);
3873+ /*
3874+ * I'd really like to just hook on the new threadid. However this always gives
3875+ * error 87. Perhaps I'm hooking to soon? No idea... however can't wait
3876+ * since I need to ensure I pick up the WM_CREATE as this is the only
3877+ * time the window can be resized in such away the content scales correctly
3878+ *
3879+ * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId);
3880+ */
3881+ if(globalhook!=NULL)
3882+ UnhookWindowsHookEx(globalhook);
3883+ globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
3884+ if(globalhook==0)
3885+ {
3886+ DEBUG("OpenPPT: SetWindowsHookEx failed\n");
3887+ ClosePPT(id);
3888+ return -1;
3889+ }
3890+ pptviewobj[id].state = PPT_STARTED;
3891+ Sleep(10);
3892+ if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
3893+ {
3894+ DEBUG("OpenPPT: CreateProcess failed\n");
3895+ ClosePPT(id);
3896+ return -1;
3897+ }
3898+ pptviewobj[id].dwProcessId = pi.dwProcessId;
3899+ pptviewobj[id].dwThreadId = pi.dwThreadId;
3900+ pptviewobj[id].hThread = pi.hThread;
3901+ pptviewobj[id].hProcess = pi.hProcess;
3902+ while(pptviewobj[id].state==PPT_STARTED)
3903+ Sleep(10);
3904+ if(gotinfo)
3905+ {
3906+ DEBUG("OpenPPT: Info loaded, no refresh\n");
3907+ pptviewobj[id].state = PPT_LOADED;
3908+ Resume(id);
3909+ }
3910+ else
3911+ {
3912+ DEBUG("OpenPPT: Get info\n");
3913+ pptviewobj[id].steps = 0;
3914+ int steps = 0;
3915+ while(pptviewobj[id].state==PPT_OPENED)
3916+ {
3917+ if(steps<=pptviewobj[id].steps)
3918+ {
3919+ Sleep(20);
3920+ DEBUG("OpenPPT: Step %d/%d\n",steps,pptviewobj[id].steps);
3921+ steps++;
3922+ NextStep(id);
3923+ }
3924+ Sleep(10);
3925+ }
3926+ DEBUG("OpenPPT: Steps %d, first slide steps %d\n",pptviewobj[id].steps,pptviewobj[id].firstSlideSteps);
3927+ SavePPTInfo(id);
3928+ if(pptviewobj[id].state==PPT_CLOSING){
3929+ ClosePPT(id);
3930+ id=-1;
3931+ }
3932+ else
3933+ RestartShow(id);
3934+ }
3935+ if(id>=0)
3936+ {
3937+ if(pptviewobj[id].mhook!=NULL)
3938+ UnhookWindowsHookEx(pptviewobj[id].mhook);
3939+ pptviewobj[id].mhook = NULL;
3940+ }
3941+ DEBUG("OpenPPT: Exit: id=%i\n", id);
3942+ return id;
3943+}
3944+// Load information about the ppt from an info.txt file.
3945+// Format:
3946+// version
3947+// filedate
3948+// filesize
3949+// slidecount
3950+// first slide steps
3951+BOOL GetPPTInfo(int id)
3952+{
3953+ struct _stat filestats;
3954+ char info[MAX_PATH];
3955+ FILE* pFile;
3956+ char buf[100];
3957+
3958+ DEBUG("GetPPTInfo: start\n");
3959+ if(_stat(pptviewobj[id].filename, &filestats)!=0)
3960+ return FALSE;
3961+ sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
3962+ int err = fopen_s(&pFile, info, "r");
3963+ if(err!=0)
3964+ {
3965+ DEBUG("GetPPTInfo: file open failed - %d\n", err);
3966+ return FALSE;
3967+ }
3968+ fgets(buf, 100, pFile); // version == 1
3969+ fgets(buf, 100, pFile);
3970+ if(filestats.st_mtime!=atoi(buf))
3971+ {
3972+ fclose (pFile);
3973+ return FALSE;
3974+ }
3975+ fgets(buf, 100, pFile);
3976+ if(filestats.st_size!=atoi(buf))
3977+ {
3978+ fclose (pFile);
3979+ return FALSE;
3980+ }
3981+ fgets(buf, 100, pFile); // slidecount
3982+ int slidecount = atoi(buf);
3983+ fgets(buf, 100, pFile); // first slide steps
3984+ int firstslidesteps = atoi(buf);
3985+ // check all the preview images still exist
3986+ for(int i = 1; i<=slidecount; i++)
3987+ {
3988+ sprintf_s(info, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, i);
3989+ if(GetFileAttributes(info)==INVALID_FILE_ATTRIBUTES)
3990+ return FALSE;
3991+ }
3992+ fclose(pFile);
3993+ pptviewobj[id].slideCount = slidecount;
3994+ pptviewobj[id].firstSlideSteps = firstslidesteps;
3995+ DEBUG("GetPPTInfo: exit ok\n");
3996+ return TRUE;
3997+}
3998+
3999+BOOL SavePPTInfo(int id)
4000+{
4001+ struct _stat filestats;
4002+ char info[MAX_PATH];
4003+ FILE* pFile;
4004+
4005+ DEBUG("SavePPTInfo: start\n");
4006+ if(_stat(pptviewobj[id].filename, &filestats)!=0)
4007+ {
4008+ DEBUG("SavePPTInfo: stat of %s failed\n", pptviewobj[id].filename);
4009+ return FALSE;
4010+ }
4011+ sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
4012+ int err = fopen_s(&pFile, info, "w");
4013+ if(err!=0)
4014+ {
4015+ DEBUG("SavePPTInfo: fopen of %s failed%i\n", info, err);
4016+ return FALSE;
4017+ }
4018+ fprintf(pFile, "1\n");
4019+ fprintf(pFile, "%u\n", filestats.st_mtime);
4020+ fprintf(pFile, "%u\n", filestats.st_size);
4021+ fprintf(pFile, "%u\n", pptviewobj[id].slideCount);
4022+ fprintf(pFile, "%u\n", pptviewobj[id].firstSlideSteps);
4023+ fclose (pFile);
4024+ DEBUG("SavePPTInfo: exit ok\n");
4025+ return TRUE;
4026+}
4027+
4028+// Get the path of the PowerPoint viewer from the registry
4029+BOOL GetPPTViewerPath(char *pptviewerpath, int strsize)
4030+{
4031+ HKEY hkey;
4032+ DWORD dwtype, dwsize;
4033+ LRESULT lresult;
4034+
4035+ DEBUG("GetPPTViewerPath: start\n");
4036+ if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
4037+ if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
4038+ return FALSE;
4039+ dwtype = REG_SZ;
4040+ dwsize = (DWORD)strsize;
4041+ lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pptviewerpath, &dwsize );
4042+ RegCloseKey(hkey);
4043+ if(lresult!=ERROR_SUCCESS)
4044+ return FALSE;
4045+ pptviewerpath[strlen(pptviewerpath)-4] = '\0'; // remove "%1" from end of key value
4046+ DEBUG("GetPPTViewerPath: exit ok\n");
4047+ return TRUE;
4048+}
4049+
4050+// Unhook the Windows hook
4051+void Unhook(int id)
4052+{
4053+ DEBUG("Unhook: start %d\n", id);
4054+ if(pptviewobj[id].hook!=NULL)
4055+ UnhookWindowsHookEx(pptviewobj[id].hook);
4056+ if(pptviewobj[id].mhook!=NULL)
4057+ UnhookWindowsHookEx(pptviewobj[id].mhook);
4058+ pptviewobj[id].hook = NULL;
4059+ pptviewobj[id].mhook = NULL;
4060+ DEBUG("Unhook: exit ok\n");
4061+}
4062+
4063+// Close the PowerPoint viewer, release resources
4064+DllExport void ClosePPT(int id)
4065+{
4066+ DEBUG("ClosePPT: start%d\n", id);
4067+ pptviewobj[id].state = PPT_CLOSED;
4068+ Unhook(id);
4069+ if(pptviewobj[id].hWnd==0)
4070+ TerminateThread(pptviewobj[id].hThread, 0);
4071+ else
4072+ PostMessage(pptviewobj[id].hWnd, WM_CLOSE, 0, 0);
4073+ CloseHandle(pptviewobj[id].hThread);
4074+ CloseHandle(pptviewobj[id].hProcess);
4075+ memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ));
4076+ DEBUG("ClosePPT: exit ok\n");
4077+ return;
4078+}
4079+// Moves the show back onto the display
4080+DllExport void Resume(int id)
4081+{
4082+ DEBUG("Resume: %d\n", id);
4083+ MoveWindow(pptviewobj[id].hWnd, pptviewobj[id].rect.left, pptviewobj[id].rect.top,
4084+ pptviewobj[id].rect.right - pptviewobj[id].rect.left,
4085+ pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
4086+ Unblank(id);
4087+}
4088+// Moves the show off the screen so it can't be seen
4089+DllExport void Stop(int id)
4090+{
4091+ DEBUG("Stop:%d\n", id);
4092+ MoveWindow(pptviewobj[id].hWnd, -32000, -32000,
4093+ pptviewobj[id].rect.right - pptviewobj[id].rect.left,
4094+ pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
4095+}
4096+
4097+// Return the total number of slides
4098+DllExport int GetSlideCount(int id)
4099+{
4100+ DEBUG("GetSlideCount:%d\n", id);
4101+ if(pptviewobj[id].state==0)
4102+ return -1;
4103+ else
4104+ return pptviewobj[id].slideCount;
4105+}
4106+
4107+// Return the number of the slide currently viewing
4108+DllExport int GetCurrentSlide(int id)
4109+{
4110+ DEBUG("GetCurrentSlide:%d\n", id);
4111+ if(pptviewobj[id].state==0)
4112+ return -1;
4113+ else
4114+ return pptviewobj[id].currentSlide;
4115+}
4116+
4117+// Take a step forwards through the show
4118+DllExport void NextStep(int id)
4119+{
4120+ DEBUG("NextStep:%d\n", id);
4121+ if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
4122+ return;
4123+ PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
4124+}
4125+
4126+// Take a step backwards through the show
4127+DllExport void PrevStep(int id)
4128+{
4129+ DEBUG("PrevStep:%d\n", id);
4130+ PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
4131+}
4132+
4133+// Blank the show (black screen)
4134+DllExport void Blank(int id)
4135+{
4136+ // B just toggles blank on/off. However pressing any key unblanks.
4137+ // So send random unmapped letter first (say 'A'), then we can
4138+ // better guarantee B will blank instead of trying to guess
4139+ // whether it was already blank or not.
4140+ DEBUG("Blank:%d\n", id);
4141+ HWND h1 = GetForegroundWindow();
4142+ HWND h2 = GetFocus();
4143+ SetForegroundWindow(pptviewobj[id].hWnd);
4144+ SetFocus(pptviewobj[id].hWnd);
4145+ Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
4146+ keybd_event((int)'A', 0, 0, 0);
4147+ keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0);
4148+ keybd_event((int)'B', 0, 0, 0);
4149+ keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0);
4150+ SetForegroundWindow(h1);
4151+ SetFocus(h2);
4152+ //PostMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'B', 0x00300001);
4153+ //PostMessage(pptviewobj[id].hWnd2, WM_CHAR, 'b', 0x00300001);
4154+ //PostMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'B', 0xC0300001);
4155+}
4156+// Unblank the show
4157+DllExport void Unblank(int id)
4158+{
4159+ DEBUG("Unblank:%d\n", id);
4160+ // Pressing any key resumes.
4161+ // For some reason SendMessage works for unblanking, but not blanking.
4162+// SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'A', 0);
4163+ SendMessage(pptviewobj[id].hWnd2, WM_CHAR, 'A', 0);
4164+// SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'A', 0);
4165+// HWND h1 = GetForegroundWindow();
4166+// HWND h2 = GetFocus();
4167+// Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
4168+// SetForegroundWindow(pptviewobj[id].hWnd);
4169+// SetFocus(pptviewobj[id].hWnd);
4170+// keybd_event((int)'A', 0, 0, 0);
4171+// SetForegroundWindow(h1);
4172+// SetFocus(h2);
4173+}
4174+
4175+// Go directly to a slide
4176+DllExport void GotoSlide(int id, int slideno)
4177+{
4178+ DEBUG("GotoSlide %i %i:\n", id, slideno);
4179+ // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work
4180+ // perhaps I was sending to the wrong window? No idea.
4181+ // Anyway fall back to keybd_event, which is OK as long we makesure
4182+ // the slideshow has focus first
4183+ char ch[10];
4184+
4185+ if(slideno<0) return;
4186+ _itoa_s(slideno, ch, 10, 10);
4187+ HWND h1 = GetForegroundWindow();
4188+ HWND h2 = GetFocus();
4189+ SetForegroundWindow(pptviewobj[id].hWnd);
4190+ SetFocus(pptviewobj[id].hWnd);
4191+ Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
4192+ for(int i=0;i<10;i++)
4193+ {
4194+ if(ch[i]=='\0') break;
4195+ keybd_event((BYTE)ch[i], 0, 0, 0);
4196+ keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0);
4197+ }
4198+ keybd_event(VK_RETURN, 0, 0, 0);
4199+ keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
4200+ SetForegroundWindow(h1);
4201+ SetFocus(h2);
4202+
4203+ //for(int i=0;i<10;i++)
4204+ //{
4205+ // if(ch[i]=='\0') break;
4206+ // SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, ch[i], 0);
4207+ // SendMessage(pptviewobj[id].hWnd2, WM_CHAR, ch[i], 0);
4208+ // SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, ch[i], 0);
4209+ //}
4210+ //SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, VK_RETURN, 0);
4211+ //SendMessage(pptviewobj[id].hWnd2, WM_CHAR, VK_RETURN, 0);
4212+ //SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, VK_RETURN, 0);
4213+ //keybd_event(VK_RETURN, 0, 0, 0);
4214+}
4215+
4216+// Restart the show from the beginning
4217+DllExport void RestartShow(int id)
4218+{
4219+ // If we just go direct to slide one, then it remembers that all other slides have
4220+ // been animated, so ends up just showing the completed slides of those slides that
4221+ // have been animated next time we advance.
4222+ // Only way I've found to get around this is to step backwards all the way through.
4223+ // Lets move the window out of the way first so the audience doesn't see this.
4224+ DEBUG("RestartShow:%d\n", id);
4225+ Stop(id);
4226+ GotoSlide(id, pptviewobj[id].slideCount);
4227+ while(pptviewobj[id].currentSlide>1)
4228+ {
4229+ PrevStep(id);
4230+ Sleep(10);
4231+ }
4232+ for(int i=0;i<=pptviewobj[id].firstSlideSteps;i++)
4233+ {
4234+ PrevStep(id);
4235+ Sleep(10);
4236+ }
4237+ Resume(id);
4238+}
4239+
4240+// This hook is started with the PPTVIEW.EXE process and waits for the
4241+// WM_CREATEWND message. At this point (and only this point) can the
4242+// window be resized to the correct size.
4243+// Release the hook as soon as we're complete to free up resources
4244+LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
4245+{
4246+ HHOOK hook = globalhook;
4247+ if(nCode==HCBT_CREATEWND)
4248+ {
4249+ char csClassName[16];
4250+ HWND hCurrWnd = (HWND)wParam;
4251+ DWORD retProcId = NULL;
4252+ GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
4253+ if((strcmp(csClassName, "paneClassDC")==0)
4254+ ||(strcmp(csClassName, "screenClass")==0))
4255+ {
4256+ int id=-1;
4257+ DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
4258+ for(int i=0; i<MAX_PPTOBJS; i++)
4259+ {
4260+ if(pptviewobj[i].dwThreadId==windowthread)
4261+ {
4262+ id=i;
4263+ break;
4264+ }
4265+ }
4266+ if(id>=0)
4267+ {
4268+ if(strcmp(csClassName, "paneClassDC")==0)
4269+ pptviewobj[id].hWnd2=hCurrWnd;
4270+ else
4271+ {
4272+ pptviewobj[id].hWnd=hCurrWnd;
4273+ CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
4274+ if(pptviewobj[id].hParentWnd!=NULL)
4275+ cw->lpcs->hwndParent = pptviewobj[id].hParentWnd;
4276+ cw->lpcs->cy=(pptviewobj[id].rect.bottom-pptviewobj[id].rect.top);
4277+ cw->lpcs->cx=(pptviewobj[id].rect.right-pptviewobj[id].rect.left);
4278+ cw->lpcs->y=-32000;
4279+ cw->lpcs->x=-32000;
4280+ }
4281+ if((pptviewobj[id].hWnd!=NULL)&&(pptviewobj[id].hWnd2!=NULL))
4282+ {
4283+ UnhookWindowsHookEx(globalhook);
4284+ globalhook=NULL;
4285+ pptviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pptviewobj[id].dwThreadId);
4286+ pptviewobj[id].mhook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInstance,pptviewobj[id].dwThreadId);
4287+ Sleep(10);
4288+ pptviewobj[id].state = PPT_OPENED;
4289+ }
4290+ }
4291+ }
4292+ }
4293+ return CallNextHookEx(hook,nCode,wParam,lParam);
4294+}
4295+
4296+// This hook exists whilst the slideshow is loading but only listens on the
4297+// slideshows thread. It listens out for mousewheel events
4298+LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
4299+{
4300+ HHOOK hook = NULL;
4301+ MSG *pMSG = (MSG *)lParam;
4302+ DWORD windowthread = GetWindowThreadProcessId(pMSG->hwnd,NULL);
4303+ int id=-1;
4304+ for(int i=0; i<MAX_PPTOBJS; i++)
4305+ {
4306+ if(pptviewobj[i].dwThreadId==windowthread)
4307+ {
4308+ id=i;
4309+ hook = pptviewobj[id].mhook;
4310+ break;
4311+ }
4312+ }
4313+ if(id>=0&&nCode==HC_ACTION&&wParam==PM_REMOVE&&pMSG->message==WM_MOUSEWHEEL)
4314+ {
4315+ if(pptviewobj[id].state!=PPT_LOADED)
4316+ {
4317+ if(pptviewobj[id].currentSlide==1)
4318+ pptviewobj[id].firstSlideSteps++;
4319+ pptviewobj[id].steps++;
4320+ }
4321+ }
4322+ return CallNextHookEx(hook, nCode, wParam, lParam);
4323+}
4324+// This hook exists whilst the slideshow is running but only listens on the
4325+// slideshows thread. It listens out for slide changes, message WM_USER+22.
4326+LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
4327+ CWPSTRUCT *cwp;
4328+ cwp = (CWPSTRUCT *)lParam;
4329+ HHOOK hook = NULL;
4330+ char filename[MAX_PATH];
4331+
4332+ DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
4333+ int id=-1;
4334+ for(int i=0; i<MAX_PPTOBJS; i++)
4335+ {
4336+ if(pptviewobj[i].dwThreadId==windowthread)
4337+ {
4338+ id=i;
4339+ hook = pptviewobj[id].hook;
4340+ break;
4341+ }
4342+ }
4343+ if((id>=0)&&(nCode==HC_ACTION))
4344+ {
4345+ if(cwp->message==WM_USER+22)
4346+ {
4347+ if(pptviewobj[id].state != PPT_LOADED)
4348+ {
4349+ if((pptviewobj[id].currentSlide>0)
4350+ && (pptviewobj[id].previewpath!=NULL&&strlen(pptviewobj[id].previewpath)>0))
4351+ {
4352+ sprintf_s(filename, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, pptviewobj[id].currentSlide);
4353+ CaptureAndSaveWindow(cwp->hwnd, filename);
4354+ }
4355+ }
4356+ if(cwp->wParam==0)
4357+ {
4358+ if(pptviewobj[id].currentSlide>0)
4359+ {
4360+ pptviewobj[id].state = PPT_LOADED;
4361+ pptviewobj[id].currentSlide = pptviewobj[id].slideCount+1;
4362+ }
4363+ }
4364+ else
4365+ {
4366+ pptviewobj[id].currentSlide = cwp->wParam - 255;
4367+ if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
4368+ pptviewobj[id].slideCount = pptviewobj[id].currentSlide;
4369+ }
4370+ }
4371+ if((pptviewobj[id].state != PPT_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT))
4372+ pptviewobj[id].state = PPT_CLOSING;
4373+ }
4374+ return CallNextHookEx(hook,nCode,wParam,lParam);
4375+}
4376+
4377+VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename)
4378+{
4379+ HBITMAP hBmp;
4380+ if ((hBmp = CaptureWindow(hWnd)) == NULL)
4381+ return;
4382+
4383+ RECT client;
4384+ GetClientRect (hWnd, &client);
4385+ UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits
4386+ UINT uiRemainderForPadding;
4387+
4388+ if ((uiRemainderForPadding = uiBytesPerRow % sizeof (DWORD)) > 0)
4389+ uiBytesPerRow += (sizeof (DWORD) - uiRemainderForPadding);
4390+
4391+ UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom;
4392+ PBYTE pDataBits;
4393+
4394+ if ((pDataBits = new BYTE [uiBytesPerAllRows]) != NULL)
4395+ {
4396+ BITMAPINFOHEADER bmi = {0};
4397+ BITMAPFILEHEADER bmf = {0};
4398+
4399+ // Prepare to get the data out of HBITMAP:
4400+ bmi.biSize = sizeof (bmi);
4401+ bmi.biPlanes = 1;
4402+ bmi.biBitCount = 24;
4403+ bmi.biHeight = client.bottom;
4404+ bmi.biWidth = client.right;
4405+
4406+ // Get it:
4407+ HDC hDC = GetDC (hWnd);
4408+ GetDIBits (hDC, hBmp, 0, client.bottom, pDataBits,
4409+ (BITMAPINFO*) &bmi, DIB_RGB_COLORS);
4410+ ReleaseDC (hWnd, hDC);
4411+
4412+ // Fill the file header:
4413+ bmf.bfOffBits = sizeof (bmf) + sizeof (bmi);
4414+ bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows;
4415+ bmf.bfType = 0x4D42;
4416+
4417+ // Writing:
4418+ FILE* pFile;
4419+ int err = fopen_s(&pFile, filename, "wb");
4420+ if (err == 0)
4421+ {
4422+ fwrite (&bmf, sizeof (bmf), 1, pFile);
4423+ fwrite (&bmi, sizeof (bmi), 1, pFile);
4424+ fwrite (pDataBits, sizeof (BYTE), uiBytesPerAllRows, pFile);
4425+ fclose (pFile);
4426+ }
4427+ delete [] pDataBits;
4428+ }
4429+ DeleteObject (hBmp);
4430+}
4431+HBITMAP CaptureWindow (HWND hWnd) {
4432+ HDC hDC;
4433+ BOOL bOk = FALSE;
4434+ HBITMAP hImage = NULL;
4435+
4436+ hDC = GetDC (hWnd);
4437+ RECT rcClient;
4438+ GetClientRect (hWnd, &rcClient);
4439+ if ((hImage = CreateCompatibleBitmap (hDC, rcClient.right, rcClient.bottom)) != NULL)
4440+ {
4441+ HDC hMemDC;
4442+ HBITMAP hDCBmp;
4443+
4444+ if ((hMemDC = CreateCompatibleDC (hDC)) != NULL)
4445+ {
4446+ hDCBmp = (HBITMAP) SelectObject (hMemDC, hImage);
4447+ HMODULE hLib = LoadLibrary("User32");
4448+ // PrintWindow works for windows outside displayable area
4449+ // but was only introduced in WinXP. BitBlt requires the window to be topmost
4450+ // and within the viewable area of the display
4451+ if(GetProcAddress(hLib, "PrintWindow")==NULL)
4452+ {
4453+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
4454+ BitBlt (hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0, 0, SRCCOPY);
4455+ SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0, SWP_NOSIZE);
4456+ }
4457+ else
4458+ {
4459+ PrintWindow(hWnd, hMemDC, 0);
4460+ }
4461+ SelectObject (hMemDC, hDCBmp);
4462+ DeleteDC (hMemDC);
4463+ bOk = TRUE;
4464+ }
4465+ }
4466+ ReleaseDC (hWnd, hDC);
4467+ if (! bOk)
4468+ {
4469+ if (hImage)
4470+ {
4471+ DeleteObject (hImage);
4472+ hImage = NULL;
4473+ }
4474+ }
4475+ return hImage;
4476+}
4477
4478=== modified file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h'
4479--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h 2008-12-10 20:40:18 +0000
4480+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h 2009-09-13 15:14:45 +0000
4481@@ -1,54 +1,54 @@
4482-
4483-#define DllExport extern "C" __declspec( dllexport )
4484-
4485-enum PPTVIEWSTATE { PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED, PPT_CLOSING};
4486-
4487-DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
4488-DllExport void ClosePPT(int id);
4489-DllExport int GetCurrentSlide(int id);
4490-DllExport int GetSlideCount(int id);
4491-DllExport void NextStep(int id);
4492-DllExport void PrevStep(int id);
4493-DllExport void GotoSlide(int id, int slideno);
4494-DllExport void RestartShow(int id);
4495-DllExport void Blank(int id);
4496-DllExport void Unblank(int id);
4497-DllExport void Stop(int id);
4498-DllExport void Resume(int id);
4499-DllExport void SetDebug(BOOL onoff);
4500-
4501-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
4502-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
4503-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
4504-BOOL GetPPTViewerPath(char *pptviewerpath, int strsize);
4505-HBITMAP CaptureWindow (HWND hWnd);
4506-VOID SaveBitmap (CHAR* filename, HBITMAP hBmp) ;
4507-VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename);
4508-BOOL GetPPTInfo(int id);
4509-BOOL SavePPTInfo(int id);
4510-
4511-
4512-void Unhook(int id);
4513-
4514-#define MAX_PPTOBJS 50
4515-
4516-struct PPTVIEWOBJ
4517-{
4518- HHOOK hook;
4519- HHOOK mhook;
4520- HWND hWnd;
4521- HWND hWnd2;
4522- HWND hParentWnd;
4523- HANDLE hProcess;
4524- HANDLE hThread;
4525- DWORD dwProcessId;
4526- DWORD dwThreadId;
4527- RECT rect;
4528- int slideCount;
4529- int currentSlide;
4530- int firstSlideSteps;
4531- int steps;
4532- char filename[MAX_PATH];
4533- char previewpath[MAX_PATH];
4534- PPTVIEWSTATE state;
4535+
4536+#define DllExport extern "C" __declspec( dllexport )
4537+
4538+enum PPTVIEWSTATE { PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED, PPT_CLOSING};
4539+
4540+DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
4541+DllExport void ClosePPT(int id);
4542+DllExport int GetCurrentSlide(int id);
4543+DllExport int GetSlideCount(int id);
4544+DllExport void NextStep(int id);
4545+DllExport void PrevStep(int id);
4546+DllExport void GotoSlide(int id, int slideno);
4547+DllExport void RestartShow(int id);
4548+DllExport void Blank(int id);
4549+DllExport void Unblank(int id);
4550+DllExport void Stop(int id);
4551+DllExport void Resume(int id);
4552+DllExport void SetDebug(BOOL onoff);
4553+
4554+LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
4555+LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
4556+LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
4557+BOOL GetPPTViewerPath(char *pptviewerpath, int strsize);
4558+HBITMAP CaptureWindow (HWND hWnd);
4559+VOID SaveBitmap (CHAR* filename, HBITMAP hBmp) ;
4560+VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename);
4561+BOOL GetPPTInfo(int id);
4562+BOOL SavePPTInfo(int id);
4563+
4564+
4565+void Unhook(int id);
4566+
4567+#define MAX_PPTOBJS 50
4568+
4569+struct PPTVIEWOBJ
4570+{
4571+ HHOOK hook;
4572+ HHOOK mhook;
4573+ HWND hWnd;
4574+ HWND hWnd2;
4575+ HWND hParentWnd;
4576+ HANDLE hProcess;
4577+ HANDLE hThread;
4578+ DWORD dwProcessId;
4579+ DWORD dwThreadId;
4580+ RECT rect;
4581+ int slideCount;
4582+ int currentSlide;
4583+ int firstSlideSteps;
4584+ int steps;
4585+ char filename[MAX_PATH];
4586+ char previewpath[MAX_PATH];
4587+ PPTVIEWSTATE state;
4588 };
4589\ No newline at end of file
4590
4591=== modified file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj'
4592--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj 2008-12-10 20:40:18 +0000
4593+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj 2009-09-13 15:14:45 +0000
4594@@ -1,203 +1,203 @@
4595-<?xml version="1.0" encoding="Windows-1252"?>
4596-<VisualStudioProject
4597- ProjectType="Visual C++"
4598- Version="9.00"
4599- Name="pptviewlib"
4600- ProjectGUID="{04CC20D1-DC5A-4189-8181-4011E3C21DCF}"
4601- RootNamespace="pptviewlib"
4602- Keyword="Win32Proj"
4603- TargetFrameworkVersion="196613"
4604- >
4605- <Platforms>
4606- <Platform
4607- Name="Win32"
4608- />
4609- </Platforms>
4610- <ToolFiles>
4611- </ToolFiles>
4612- <Configurations>
4613- <Configuration
4614- Name="Debug|Win32"
4615- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
4616- IntermediateDirectory="$(ConfigurationName)"
4617- ConfigurationType="2"
4618- CharacterSet="2"
4619- >
4620- <Tool
4621- Name="VCPreBuildEventTool"
4622- />
4623- <Tool
4624- Name="VCCustomBuildTool"
4625- />
4626- <Tool
4627- Name="VCXMLDataGeneratorTool"
4628- />
4629- <Tool
4630- Name="VCWebServiceProxyGeneratorTool"
4631- />
4632- <Tool
4633- Name="VCMIDLTool"
4634- />
4635- <Tool
4636- Name="VCCLCompilerTool"
4637- Optimization="0"
4638- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
4639- MinimalRebuild="true"
4640- BasicRuntimeChecks="3"
4641- RuntimeLibrary="3"
4642- UsePrecompiledHeader="0"
4643- WarningLevel="3"
4644- DebugInformationFormat="4"
4645- />
4646- <Tool
4647- Name="VCManagedResourceCompilerTool"
4648- />
4649- <Tool
4650- Name="VCResourceCompilerTool"
4651- />
4652- <Tool
4653- Name="VCPreLinkEventTool"
4654- />
4655- <Tool
4656- Name="VCLinkerTool"
4657- LinkIncremental="2"
4658- ModuleDefinitionFile=""
4659- GenerateDebugInformation="true"
4660- SubSystem="2"
4661- TargetMachine="1"
4662- />
4663- <Tool
4664- Name="VCALinkTool"
4665- />
4666- <Tool
4667- Name="VCManifestTool"
4668- />
4669- <Tool
4670- Name="VCXDCMakeTool"
4671- />
4672- <Tool
4673- Name="VCBscMakeTool"
4674- />
4675- <Tool
4676- Name="VCFxCopTool"
4677- />
4678- <Tool
4679- Name="VCAppVerifierTool"
4680- />
4681- <Tool
4682- Name="VCPostBuildEventTool"
4683- />
4684- </Configuration>
4685- <Configuration
4686- Name="Release|Win32"
4687- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
4688- IntermediateDirectory="$(ConfigurationName)"
4689- ConfigurationType="2"
4690- CharacterSet="1"
4691- WholeProgramOptimization="1"
4692- >
4693- <Tool
4694- Name="VCPreBuildEventTool"
4695- />
4696- <Tool
4697- Name="VCCustomBuildTool"
4698- />
4699- <Tool
4700- Name="VCXMLDataGeneratorTool"
4701- />
4702- <Tool
4703- Name="VCWebServiceProxyGeneratorTool"
4704- />
4705- <Tool
4706- Name="VCMIDLTool"
4707- />
4708- <Tool
4709- Name="VCCLCompilerTool"
4710- Optimization="2"
4711- EnableIntrinsicFunctions="true"
4712- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
4713- RuntimeLibrary="2"
4714- EnableFunctionLevelLinking="true"
4715- UsePrecompiledHeader="2"
4716- WarningLevel="3"
4717- DebugInformationFormat="3"
4718- />
4719- <Tool
4720- Name="VCManagedResourceCompilerTool"
4721- />
4722- <Tool
4723- Name="VCResourceCompilerTool"
4724- />
4725- <Tool
4726- Name="VCPreLinkEventTool"
4727- />
4728- <Tool
4729- Name="VCLinkerTool"
4730- LinkIncremental="1"
4731- ModuleDefinitionFile="pptviewlib.def"
4732- GenerateDebugInformation="true"
4733- SubSystem="2"
4734- OptimizeReferences="2"
4735- EnableCOMDATFolding="2"
4736- TargetMachine="1"
4737- />
4738- <Tool
4739- Name="VCALinkTool"
4740- />
4741- <Tool
4742- Name="VCManifestTool"
4743- />
4744- <Tool
4745- Name="VCXDCMakeTool"
4746- />
4747- <Tool
4748- Name="VCBscMakeTool"
4749- />
4750- <Tool
4751- Name="VCFxCopTool"
4752- />
4753- <Tool
4754- Name="VCAppVerifierTool"
4755- />
4756- <Tool
4757- Name="VCPostBuildEventTool"
4758- />
4759- </Configuration>
4760- </Configurations>
4761- <References>
4762- </References>
4763- <Files>
4764- <Filter
4765- Name="Source Files"
4766- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
4767- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
4768- >
4769- <File
4770- RelativePath=".\pptviewlib.cpp"
4771- >
4772- </File>
4773- <File
4774- RelativePath=".\README.TXT"
4775- >
4776- </File>
4777- </Filter>
4778- <Filter
4779- Name="Header Files"
4780- Filter="h;hpp;hxx;hm;inl;inc;xsd"
4781- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
4782- >
4783- <File
4784- RelativePath=".\pptviewlib.h"
4785- >
4786- </File>
4787- </Filter>
4788- <Filter
4789- Name="Resource Files"
4790- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
4791- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
4792- >
4793- </Filter>
4794- </Files>
4795- <Globals>
4796- </Globals>
4797-</VisualStudioProject>
4798+<?xml version="1.0" encoding="Windows-1252"?>
4799+<VisualStudioProject
4800+ ProjectType="Visual C++"
4801+ Version="9.00"
4802+ Name="pptviewlib"
4803+ ProjectGUID="{04CC20D1-DC5A-4189-8181-4011E3C21DCF}"
4804+ RootNamespace="pptviewlib"
4805+ Keyword="Win32Proj"
4806+ TargetFrameworkVersion="196613"
4807+ >
4808+ <Platforms>
4809+ <Platform
4810+ Name="Win32"
4811+ />
4812+ </Platforms>
4813+ <ToolFiles>
4814+ </ToolFiles>
4815+ <Configurations>
4816+ <Configuration
4817+ Name="Debug|Win32"
4818+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
4819+ IntermediateDirectory="$(ConfigurationName)"
4820+ ConfigurationType="2"
4821+ CharacterSet="2"
4822+ >
4823+ <Tool
4824+ Name="VCPreBuildEventTool"
4825+ />
4826+ <Tool
4827+ Name="VCCustomBuildTool"
4828+ />
4829+ <Tool
4830+ Name="VCXMLDataGeneratorTool"
4831+ />
4832+ <Tool
4833+ Name="VCWebServiceProxyGeneratorTool"
4834+ />
4835+ <Tool
4836+ Name="VCMIDLTool"
4837+ />
4838+ <Tool
4839+ Name="VCCLCompilerTool"
4840+ Optimization="0"
4841+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
4842+ MinimalRebuild="true"
4843+ BasicRuntimeChecks="3"
4844+ RuntimeLibrary="3"
4845+ UsePrecompiledHeader="0"
4846+ WarningLevel="3"
4847+ DebugInformationFormat="4"
4848+ />
4849+ <Tool
4850+ Name="VCManagedResourceCompilerTool"
4851+ />
4852+ <Tool
4853+ Name="VCResourceCompilerTool"
4854+ />
4855+ <Tool
4856+ Name="VCPreLinkEventTool"
4857+ />
4858+ <Tool
4859+ Name="VCLinkerTool"
4860+ LinkIncremental="2"
4861+ ModuleDefinitionFile=""
4862+ GenerateDebugInformation="true"
4863+ SubSystem="2"
4864+ TargetMachine="1"
4865+ />
4866+ <Tool
4867+ Name="VCALinkTool"
4868+ />
4869+ <Tool
4870+ Name="VCManifestTool"
4871+ />
4872+ <Tool
4873+ Name="VCXDCMakeTool"
4874+ />
4875+ <Tool
4876+ Name="VCBscMakeTool"
4877+ />
4878+ <Tool
4879+ Name="VCFxCopTool"
4880+ />
4881+ <Tool
4882+ Name="VCAppVerifierTool"
4883+ />
4884+ <Tool
4885+ Name="VCPostBuildEventTool"
4886+ />
4887+ </Configuration>
4888+ <Configuration
4889+ Name="Release|Win32"
4890+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
4891+ IntermediateDirectory="$(ConfigurationName)"
4892+ ConfigurationType="2"
4893+ CharacterSet="1"
4894+ WholeProgramOptimization="1"
4895+ >
4896+ <Tool
4897+ Name="VCPreBuildEventTool"
4898+ />
4899+ <Tool
4900+ Name="VCCustomBuildTool"
4901+ />
4902+ <Tool
4903+ Name="VCXMLDataGeneratorTool"
4904+ />
4905+ <Tool
4906+ Name="VCWebServiceProxyGeneratorTool"
4907+ />
4908+ <Tool
4909+ Name="VCMIDLTool"
4910+ />
4911+ <Tool
4912+ Name="VCCLCompilerTool"
4913+ Optimization="2"
4914+ EnableIntrinsicFunctions="true"
4915+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
4916+ RuntimeLibrary="2"
4917+ EnableFunctionLevelLinking="true"
4918+ UsePrecompiledHeader="2"
4919+ WarningLevel="3"
4920+ DebugInformationFormat="3"
4921+ />
4922+ <Tool
4923+ Name="VCManagedResourceCompilerTool"
4924+ />
4925+ <Tool
4926+ Name="VCResourceCompilerTool"
4927+ />
4928+ <Tool
4929+ Name="VCPreLinkEventTool"
4930+ />
4931+ <Tool
4932+ Name="VCLinkerTool"
4933+ LinkIncremental="1"
4934+ ModuleDefinitionFile="pptviewlib.def"
4935+ GenerateDebugInformation="true"
4936+ SubSystem="2"
4937+ OptimizeReferences="2"
4938+ EnableCOMDATFolding="2"
4939+ TargetMachine="1"
4940+ />
4941+ <Tool
4942+ Name="VCALinkTool"
4943+ />
4944+ <Tool
4945+ Name="VCManifestTool"
4946+ />
4947+ <Tool
4948+ Name="VCXDCMakeTool"
4949+ />
4950+ <Tool
4951+ Name="VCBscMakeTool"
4952+ />
4953+ <Tool
4954+ Name="VCFxCopTool"
4955+ />
4956+ <Tool
4957+ Name="VCAppVerifierTool"
4958+ />
4959+ <Tool
4960+ Name="VCPostBuildEventTool"
4961+ />
4962+ </Configuration>
4963+ </Configurations>
4964+ <References>
4965+ </References>
4966+ <Files>
4967+ <Filter
4968+ Name="Source Files"
4969+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
4970+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
4971+ >
4972+ <File
4973+ RelativePath=".\pptviewlib.cpp"
4974+ >
4975+ </File>
4976+ <File
4977+ RelativePath=".\README.TXT"
4978+ >
4979+ </File>
4980+ </Filter>
4981+ <Filter
4982+ Name="Header Files"
4983+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
4984+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
4985+ >
4986+ <File
4987+ RelativePath=".\pptviewlib.h"
4988+ >
4989+ </File>
4990+ </Filter>
4991+ <Filter
4992+ Name="Resource Files"
4993+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
4994+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
4995+ >
4996+ </Filter>
4997+ </Files>
4998+ <Globals>
4999+ </Globals>
5000+</VisualStudioProject>
The diff has been truncated for viewing.