Java tutorial
/* * Copyright (C) 2015 team-cachebox.de * * Licensed under the : GNU General Public License (GPL); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/gpl.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package CB_UI_Base.GL_UI.Controls.html; import java.util.List; import org.slf4j.LoggerFactory; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.GlyphLayout; import com.badlogic.gdx.utils.Align; import CB_Translation_Base.TranslationEngine.Translation; import CB_UI_Base.Enums.WrapType; import CB_UI_Base.GL_UI.CB_View_Base; import CB_UI_Base.GL_UI.GL_View_Base; import CB_UI_Base.GL_UI.IRunOnGL; import CB_UI_Base.GL_UI.Controls.Box; import CB_UI_Base.GL_UI.Controls.EditTextField; import CB_UI_Base.GL_UI.Controls.Image; import CB_UI_Base.GL_UI.Controls.ImageButton; import CB_UI_Base.GL_UI.Controls.ImageLoader; import CB_UI_Base.GL_UI.Controls.LinkLabel; import CB_UI_Base.GL_UI.Controls.ScrollBox; import CB_UI_Base.GL_UI.Controls.List.ListViewBase.IListPosChanged; import CB_UI_Base.GL_UI.Controls.List.ListViewItemBase; import CB_UI_Base.GL_UI.Controls.List.Scrollbar; import CB_UI_Base.GL_UI.Controls.List.V_ListView; import CB_UI_Base.GL_UI.Controls.MessageBox.GL_MsgBox; import CB_UI_Base.GL_UI.GL_Listener.GL; import CB_UI_Base.GL_UI.utils.ColorDrawable; import CB_UI_Base.Math.CB_RectF; import CB_UI_Base.Math.UI_Size_Base; import CB_UI_Base.graphics.FontCache; import CB_UI_Base.settings.CB_UI_Base_Settings; import CB_Utils.Lists.CB_List; import CB_Utils.Log.Log; import CB_Utils.Log.Trace; import CB_Utils.Util.HSV_Color; import net.htmlparser.jericho.Source; /** * @author Longri */ public class HtmlView extends ScrollBox implements ListLayout { private boolean textOnly = false; private EditTextField textOnlyField; final static org.slf4j.Logger log = LoggerFactory.getLogger(HtmlView.class); static int margin; private Box contentBox; private List<Html_Segment> segmentList; private CB_List<CB_View_Base> segmentViewList; public HtmlView(CB_RectF rec) { super(rec); margin = UI_Size_Base.that.getMargin() / 2; this.setClickable(true); } public void showHtml(final String html) throws Exception { clearHtml(); if (textOnly) { String htmlSource = html.replace("</p>", "</p><br>"); Source source = new Source(htmlSource); StringBuilder sb = new StringBuilder(); source.getRenderer().appendTo(sb); String text = sb.toString(); textOnlyField = new EditTextField(this, this, null, this.name + " textOnlyField", WrapType.WRAPPED); textOnlyField.dontShowSoftKeyBoardOnFocus(); textOnlyField.setNoBorders(); textOnlyField.setText(text); textOnlyField.setEditable(false); textOnlyField.showFromLineNo(0); this.addChildDirekt(textOnlyField); this.setVirtualHeight(this.getHeight()); this.scrollTo(0); // this.setUndragable(); this.setDragable(); } else { this.setDragable(); if (textOnlyField != null) { this.removeChildsDirekt(textOnlyField); textOnlyField = null; } if (segmentList != null) { segmentList.clear(); } segmentViewList = new CB_List<CB_View_Base>(); Exception any = null; try { Source source = new CB_FormatedHtmlSource(html); segmentList = new CB_Html_Renderer(source).getElementList(); addViewsToBox(segmentList, segmentViewList, this.getWidth() /** 2*/ , this); } catch (Exception e) { any = e; } layout(segmentViewList); if (any != null) throw any; } } static int test = 0; // TODO Calculate innerWidth to max line width! HtmlView can scroll // horizontal public static void addViewsToBox(List<Html_Segment> segmentList, CB_List<CB_View_Base> segmentViewList, float innerWidth, final ListLayout relayout) { for (int i = 0, n = segmentList.size(); i < n; i++) { Html_Segment seg = segmentList.get(i); switch (seg.segmentTyp) { case HR: addHR(segmentViewList, (Html_Segment_HR) seg, innerWidth); break; case Image: addImage(segmentViewList, seg, relayout, innerWidth); break; case TextBlock: addTextBlog(segmentViewList, (Html_Segment_TextBlock) seg, innerWidth - margin); break; case List: addListBlog(segmentViewList, (HTML_Segment_List) seg, innerWidth - margin); break; case Input: addInput(segmentViewList, (Html_Segment_Input) seg, relayout, innerWidth); break; case Table: addTableBlog(segmentViewList, (HTML_Segment_Table) seg, innerWidth); break; default: break; } } } private static float addInput(final CB_List<CB_View_Base> segmentViewList, final Html_Segment_Input seg, final ListLayout relayout, float innerWidth) { if (!seg.value.startsWith("att_")) return 0; ImageLoader img = new ImageLoader(); img.setImage(seg.imagePath); ImageButton imgBtn = new ImageButton(img) { @Override public void onResized(CB_RectF rec) { super.onResized(rec); this.setWidth(this.getHeight()); GL.that.RunOnGL(new IRunOnGL() { @Override public void run() { relayout.layout(segmentViewList); } }); } }; imgBtn.setWidth(imgBtn.getHeight()); imgBtn.setOnClickListener(new OnClickListener() { @Override public boolean onClick(GL_View_Base v, int x, int y, int pointer, int button) { GL_MsgBox.Show(Translation.Get(seg.value)); return true; } }); segmentViewList.add(imgBtn); return imgBtn.getHeight(); } private static float addListBlog(CB_List<CB_View_Base> segmentViewList, HTML_Segment_List seg, float innerWidth) { Html_ListView ListcontentBox = new Html_ListView(innerWidth, seg); segmentViewList.add(ListcontentBox); return ListcontentBox.getHeight(); } private static float addTableBlog(CB_List<CB_View_Base> segmentViewList, HTML_Segment_Table seg, float innerWidth) { Html_TableView TableContentBox = new Html_TableView(innerWidth, seg); segmentViewList.add(TableContentBox); return TableContentBox.getHeight(); } @Override public void layout(CB_List<CB_View_Base> segmentViewList) { if (contentBox != null) contentBox.removeChildsDirekt(); contentBox = addViewsToContentBox(this, segmentViewList); this.addChild(contentBox); this.setVirtualHeight(contentBox.getHeight()); this.scrollTo(0); } static Box addViewsToContentBox(CB_View_Base parent, CB_List<CB_View_Base> segmentViewList) { Box content = new Box(parent, "topContent"); int testcount = 0; Log.debug(log, "HTML View Layout"); Log.debug(log, " " + Trace.getCallerName(0)); Log.debug(log, " " + Trace.getCallerName(1)); Log.debug(log, " " + Trace.getCallerName(2)); float innerWidth = parent.getInnerWidth() - (margin * 2); int maxAttributeButtonsPerLine = (int) (innerWidth / (UI_Size_Base.that.getButtonHeight())); float contentHeight = 0; int attLines = 1; for (int i = 0, n = segmentViewList.size(); i < n; i++) { CB_View_Base view = segmentViewList.get(i); if (view instanceof ImageButton) { if (testcount++ > maxAttributeButtonsPerLine) { attLines++; testcount = 0; } } else { contentHeight += view.getHeight(); } } contentHeight += (attLines * UI_Size_Base.that.getButtonHeight()); content.setWidth(innerWidth); content.setClickable(true); content.setHeight(contentHeight); content.setZeroPos(); content.setX(margin); content.setMargins(0, 0); content.initRow(); testcount = 0; float maxWidth = 0; for (int i = 0, n = segmentViewList.size(); i < n; i++) { CB_View_Base view = segmentViewList.get(i); view.measureRec(); maxWidth = Math.max(maxWidth, view.getWidth()); if (view instanceof Image) { content.addLast(segmentViewList.get(i)); } else if (view instanceof ImageButton) { if (testcount++ > maxAttributeButtonsPerLine) { content.addLast(segmentViewList.get(i), FIXED); testcount = 0; } else { content.addNext(segmentViewList.get(i), FIXED); } } else { content.addLast(segmentViewList.get(i), FIXED); } } content.setWidth(maxWidth); for (int i = 0, n = content.getchilds().size(); i < n; i++) { GL_View_Base child = content.getChild(i); if (child instanceof Html_ListView) { // move tab on x float tabX = content.getWidth() - ((Html_ListView) child).getContentWidth(); child.setX(tabX); // child.setX(0); } } return content; } private static float addHR(CB_List<CB_View_Base> segmentViewList, Html_Segment_HR seg, float innerWidth) { HrView hrView = new HrView(0, 0, innerWidth, seg.hrsize, "hr"); hrView.setBackground(new ColorDrawable((HSV_Color) getColor(seg.getColor()))); segmentViewList.add(hrView); return hrView.getHeight(); } private static float lastRelayoutStateTime = 0; private static float addImage(final CB_List<CB_View_Base> segmentViewList, Html_Segment seg, final ListLayout relayout, float innerWidth) { Image img = new Image(0, 0, innerWidth, 50, "Html-Image", true) { @Override public void onResized(CB_RectF rec) { super.onResized(rec); GL.that.RunOnGL(new IRunOnGL() { @Override public void run() { if (lastRelayoutStateTime == GL.that.getStateTime()) return; lastRelayoutStateTime = GL.that.getStateTime(); relayout.layout(segmentViewList); } }); } }; img.setHAlignment(seg.hAlignment); img.setImageURL(seg.formatedText); img.forceImageLoad(); segmentViewList.add(img); return img.getHeight(); } private static float addTextBlog(CB_List<CB_View_Base> segmentViewList, Html_Segment_TextBlock seg, float innerWidth) { boolean markUp = !seg.hyperLinkList.isEmpty(); BitmapFont font = FontCache.get(markUp, seg.getFontFamily(), seg.getFontStyle(), seg.getFontSize()); GlyphLayout layout = new GlyphLayout(); // dont do this every frame! // Store it as member layout.setText(font, seg.formatedText, getColor(Color.BLACK), innerWidth - (margin * 2), Align.left, true); float segHeight = layout.height + (margin * 2); parseHyperLinks(seg, "http://"); parseHyperLinks(seg, "www."); LinkLabel lbl = new LinkLabel("HtmlView" + " lbl", 0, 0, innerWidth - (margin * 2), segHeight); if (markUp) { lbl.setMarkupEnabled(true); } lbl.setTextColor(getColor(seg.getFontColor())); lbl.setFont(font).setHAlignment(seg.hAlignment); if (markUp) { lbl.addHyperlinks(seg.hyperLinkList); } lbl.setWrappedText(seg.formatedText); lbl.setUnderline(seg.underline); lbl.setStrikeout(seg.strikeOut); segmentViewList.add(lbl); return lbl.getHeight(); } private static Color getColor(Color color) { if (CB_UI_Base_Settings.nightMode.getValue()) color = HSV_Color.colorMatrixManipulation(color, HSV_Color.NIGHT_COLOR_MATRIX); return color; } private static void parseHyperLinks(Html_Segment_TextBlock seg, String hyperLinkTag) { try { if (seg.formatedText.contains(hyperLinkTag)) { // add to hyperLings int start = seg.formatedText.indexOf(hyperLinkTag); int end1 = seg.formatedText.indexOf(" ", start); int end2 = seg.formatedText.indexOf("\r", start); int end3 = seg.formatedText.indexOf("\n", start); if (end1 < 0) end1 = Integer.MAX_VALUE; if (end2 < 0) end2 = Integer.MAX_VALUE; if (end3 < 0) end3 = Integer.MAX_VALUE; int end = Math.min(Math.min(end1, end2), end3); if (end == Integer.MAX_VALUE) { end = seg.formatedText.length(); } String link = seg.formatedText.substring(start, end); if (link.endsWith(")") || link.endsWith("]") || link.endsWith("}")) { link = seg.formatedText.substring(start, end - 1); } HyperLinkText hyper = new HyperLinkText(link.trim(), link.trim()); seg.hyperLinkList.add(hyper); } } catch (Exception e) { Log.err(log, "parseHyperLinks", e); } } @Override public void dispose() { clearHtml(); super.dispose(); } private void clearHtml() { if (contentBox == null) return; synchronized (contentBox) { Log.debug(log, "Clear html"); this.removeChilds(); if (segmentViewList != null) { for (CB_View_Base view : segmentViewList) { if (view != null) { view.dispose(); } view = null; } segmentViewList.clear(); } if (segmentList != null) { for (Html_Segment segment : segmentList) { if (segment != null) { segment.dispose(); } segment = null; } segmentList.clear(); } if (contentBox != null) { for (GL_View_Base view : contentBox.getchilds()) { if (view != null) { view.dispose(); } view = null; } contentBox.dispose(); contentBox = null; } } } /** * Return true, if this in text only mode! * * @return */ public boolean getTextOnly() { return textOnly; } public void setTextOnly(boolean value) { textOnly = value; } private int touchXPos; private float lastContentXPos; @Override public boolean onTouchDown(int x, int y, int pointer, int button) { touchXPos = x; lastContentXPos = contentBox.getX(); return true; // muss behandelt werden, da sonnst kein onTouchDragged() // ausgelsst wird. } @Override public boolean onTouchDragged(int x, int y, int pointer, boolean KineticPan) { int draged = x - touchXPos; contentBox.setX(lastContentXPos + draged); if (contentBox.getX() > margin) contentBox.setX(margin); else if (contentBox.getMaxX() < this.innerWidth) contentBox.setX(this.innerWidth - contentBox.getWidth()); return true; } @Override protected void initScrollBox() { // todo: check to have no scroll(? - margin) oder rec.getHalfHeight() virtualHeight = this.getHeight(); // Override onTouDown from ListView and return false for consume // onTouchDown Event on HtmlView! lv = new V_ListView(this, this, "ListView-" + name) { @Override public boolean onTouchDown(int x, int y, int pointer, int button) { super.onTouchDown(x, y, pointer, button); return false; } }; lv.setClickable(true); item = new ListViewItemBase(this, 0, "ListViewItem-" + name) { @Override protected void SkinIsChanged() { } @Override protected void Initial() { isInitial = true; } }; item.setHeight(virtualHeight); item.setClickable(true); thisAdapter = new CustomAdapter(); lv.setDisposeFlag(false); lv.setBaseAdapter(thisAdapter); Layout(); final Scrollbar scrollBar = new Scrollbar(lv); lv.addListPosChangedEventHandler(new IListPosChanged() { @Override public void ListPosChanged() { scrollBar.ScrollPositionChanged(); } }); this.childs.add(lv); this.childs.add(scrollBar); } }