1 package org
.argeo
.app
.swt
.docbook
;
3 import static org
.argeo
.app
.docbook
.DbkAcrUtils
.isDbk
;
4 import static org
.argeo
.app
.docbook
.DbkType
.para
;
6 import java
.util
.ArrayList
;
8 import java
.util
.Optional
;
10 import org
.argeo
.api
.acr
.Content
;
11 import org
.argeo
.api
.cms
.ux
.Cms2DSize
;
12 import org
.argeo
.api
.cms
.ux
.CmsEditable
;
13 import org
.argeo
.app
.docbook
.DbkAttr
;
14 import org
.argeo
.app
.docbook
.DbkType
;
15 import org
.argeo
.cms
.swt
.CmsSwtUtils
;
16 import org
.argeo
.cms
.swt
.SwtEditablePart
;
17 import org
.argeo
.cms
.swt
.acr
.AbstractPageViewer
;
18 import org
.argeo
.cms
.swt
.acr
.SwtSection
;
19 import org
.argeo
.cms
.swt
.acr
.SwtSectionPart
;
20 import org
.argeo
.cms
.swt
.widgets
.EditableText
;
21 import org
.argeo
.cms
.swt
.widgets
.StyledControl
;
22 import org
.eclipse
.swt
.SWT
;
23 import org
.eclipse
.swt
.layout
.GridData
;
24 import org
.eclipse
.swt
.widgets
.Composite
;
25 import org
.eclipse
.swt
.widgets
.Control
;
27 /** Displays DocBook content. */
28 public class DocBookViewer
extends AbstractPageViewer
{
30 private TextInterpreter textInterpreter
= new DbkTextInterpreter();
31 private DbkImageManager imageManager
;
33 private TextSection mainSection
;
35 private boolean showMainTitle
= true;
37 private Integer maxMediaWidth
= null;
38 private String defaultSectionStyle
;
40 public DocBookViewer(Composite parent
, int style
, Content item
, CmsEditable cmsEditable
) {
41 super(parent
, style
, cmsEditable
);
42 imageManager
= new DbkImageManager(item
);
44 for (Content child
: item
) {
45 if (child
.hasContentClass(DbkType
.article
)) {
46 if (mainSection
!= null)
47 throw new IllegalStateException("Main section already created");
48 mainSection
= new TextSection(parent
, 0, child
);
49 mainSection
.setLayoutData(CmsSwtUtils
.fillAll());
55 protected void refresh(Control control
) {
56 if (!(control
instanceof SwtSection
))
58 // long begin = System.currentTimeMillis();
59 SwtSection section
= (SwtSection
) control
;
60 if (section
instanceof TextSection
) {
61 CmsSwtUtils
.clear(mainSection
);
62 refreshTextSection(mainSection
);
65 // long duration = System.currentTimeMillis() - begin;
66 // System.out.println(duration + " ms - " + DbkUtils.getTitle(section.getNode()));
70 protected void refreshTextSection(TextSection section
) {
71 Content sectionContent
= section
.getContent();
73 Optional
<String
> roleAttr
= sectionContent
.get(DbkAttr
.role
, String
.class);
74 String style
= roleAttr
.orElse(section
.getDefaultTextStyle());
76 CmsSwtUtils
.style(section
, style
);
79 Optional
<Content
> titleContent
= sectionContent
.soleChild(DbkType
.title
.qName());
81 if (titleContent
.isPresent()) {
82 boolean showTitle
= getMainSection() == section ? showMainTitle
: true;
84 if (section
.getHeader() == null)
85 section
.createHeader();
86 DbkSectionTitle title
= newSectionTitle(section
, titleContent
.get());
87 title
.setLayoutData(CmsSwtUtils
.fillWidth());
92 boolean processingSubSections
= false;
93 for (Content child
: section
.getContent()) {
94 if (child
.hasContentClass(DbkType
.section
)) {
95 processingSubSections
= true;
96 TextSection childSection
= newTextSection(section
, child
); // new TextSection(section, 0, child);
97 childSection
.setLayoutData(CmsSwtUtils
.fillWidth());
98 refreshTextSection(childSection
);
100 if (processingSubSections
)
101 throw new IllegalStateException(child
+ " is below a subsection");
102 SwtSectionPart sectionPart
= null;
103 if (child
.hasContentClass(DbkType
.para
)) {
104 sectionPart
= newParagraph(section
, child
);
105 } else if (child
.hasContentClass(DbkType
.mediaobject
)) {
106 if (child
.hasChild(DbkType
.imageobject
)) {
107 sectionPart
= newImg(section
, child
);
108 } else if (child
.hasChild(DbkType
.videoobject
)) {
109 sectionPart
= newVideo(section
, child
);
111 throw new IllegalArgumentException("Unsupported media object " + child
);
113 } else if (isDbk(child
, DbkType
.info
)) {
114 // TODO enrich UI based on info
115 } else if (isDbk(child
, DbkType
.title
)) {
117 // TODO check that it is first?
119 throw new IllegalArgumentException("Unsupported type for " + child
);
121 if (sectionPart
!= null && sectionPart
instanceof Control
)
122 ((Control
) sectionPart
).setLayoutData(CmsSwtUtils
.fillWidth());
127 protected void updateContent(SwtEditablePart part
) {
128 if (part
instanceof SwtSectionPart
) {
129 SwtSectionPart sectionPart
= (SwtSectionPart
) part
;
130 Content partContent
= sectionPart
.getContent();
132 if (part
instanceof StyledControl
&& (sectionPart
.getSection() instanceof TextSection
)) {
133 TextSection section
= (TextSection
) sectionPart
.getSection();
134 StyledControl styledControl
= (StyledControl
) part
;
135 if (isDbk(partContent
, para
)) {
136 Optional
<String
> roleAttr
= partContent
.get(DbkAttr
.role
.qName(), String
.class);
137 String style
= roleAttr
.orElse(section
.getDefaultTextStyle());
138 styledControl
.setStyle(style
);
141 // use control AFTER setting style, since it may have been reset
143 if (part
instanceof EditableText
) {
144 EditableText paragraph
= (EditableText
) part
;
145 if (paragraph
== getEdited())
146 paragraph
.setText(textInterpreter
.raw(partContent
));
148 paragraph
.setText(textInterpreter
.readSimpleHtml(partContent
));
149 // paragraph.setText(textInterpreter.readSimpleHtml(partContent));
151 } else if (part
instanceof DbkImg
) {
152 DbkImg editableImage
= (DbkImg
) part
;
153 imageManager
.load(partContent
, part
.getControl(), editableImage
.getPreferredImageSize(), null);
154 } else if (part
instanceof DbkVideo
) {
155 DbkVideo video
= (DbkVideo
) part
;
156 video
.load(part
.getControl());
158 } else if (part
instanceof DbkSectionTitle
) {
159 DbkSectionTitle title
= (DbkSectionTitle
) part
;
160 title
.setStyle(title
.getSection().getTitleStyle());
161 // use control AFTER setting style
162 if (title
== getEdited())
163 title
.setText(textInterpreter
.read(title
.getContent()));
165 title
.setText(textInterpreter
.readSimpleHtml(title
.getContent()));
169 /** To be overridden in order to provide additional SectionPart types */
170 protected TextSection
newTextSection(SwtSection section
, Content node
) {
171 return new TextSection(section
, SWT
.NONE
, node
);
174 protected Paragraph
newParagraph(TextSection parent
, Content node
) {
175 Paragraph paragraph
= new Paragraph(parent
, parent
.getStyle(), node
);
176 updateContent(paragraph
);
177 paragraph
.setLayoutData(CmsSwtUtils
.fillWidth());
178 paragraph
.setMouseListener(getMouseListener());
179 paragraph
.setFocusListener(getFocusListener());
183 protected DbkSectionTitle
newSectionTitle(TextSection parent
, Content titleNode
) {
184 int style
= parent
.getStyle();
185 Composite titleParent
= newSectionHeader(parent
);
186 if (parent
.isTitleReadOnly())
187 style
= style
| SWT
.READ_ONLY
;
188 DbkSectionTitle title
= new DbkSectionTitle(titleParent
, style
, titleNode
);
189 updateContent(title
);
190 title
.setMouseListener(getMouseListener());
191 title
.setFocusListener(getFocusListener());
195 protected DbkImg
newImg(TextSection parent
, Content node
) {
196 DbkImg img
= new DbkImg(parent
, parent
.getStyle(), node
, imageManager
);
198 if (maxMediaWidth
!= null) {
199 imgGd
= new GridData(SWT
.CENTER
, SWT
.FILL
, false, false);
200 imgGd
.widthHint
= maxMediaWidth
;
201 img
.setPreferredSize(new Cms2DSize(maxMediaWidth
, 0));
203 imgGd
= CmsSwtUtils
.grabWidth(SWT
.CENTER
, SWT
.DEFAULT
);
205 img
.setLayoutData(imgGd
);
207 img
.setMouseListener(getMouseListener());
208 img
.setFocusListener(getFocusListener());
212 protected DbkVideo
newVideo(TextSection parent
, Content node
) {
213 DbkVideo video
= new DbkVideo(parent
, getCmsEditable().canEdit() ? SWT
.NONE
: SWT
.READ_ONLY
, node
);
215 if (maxMediaWidth
!= null) {
216 gd
= new GridData(SWT
.CENTER
, SWT
.FILL
, false, false);
218 // gd.widthHint = maxMediaWidth;
219 // gd.heightHint = (int) (gd.heightHint * 0.5625);
221 gd
= new GridData(SWT
.CENTER
, SWT
.FILL
, false, false);
222 // gd.widthHint = video.getWidth();
223 // gd.heightHint = video.getHeight();
225 video
.setLayoutData(gd
);
226 updateContent(video
);
231 * To be overridden in order to provide additional processing at the section
234 * @return the parent to use for the {@link DbkSectionTitle}, by default
235 * {@link SwtSection#getHeader()}
237 protected Composite
newSectionHeader(TextSection section
) {
238 return section
.getHeader();
241 protected List
<String
> getAvailableStyles(SwtEditablePart editablePart
) {
242 return new ArrayList
<>();
245 public TextSection
getMainSection() {
249 public void setShowMainTitle(boolean showMainTitle
) {
250 this.showMainTitle
= showMainTitle
;
253 public String
getDefaultSectionStyle() {
254 return defaultSectionStyle
;
257 public void setDefaultSectionStyle(String defaultSectionStyle
) {
258 this.defaultSectionStyle
= defaultSectionStyle
;
261 public void setMaxMediaWidth(Integer maxMediaWidth
) {
262 this.maxMediaWidth
= maxMediaWidth
;
266 public Control
getControl() {