2014-06-30 04:04:32 +00:00
/ *
XOWA : the XOWA Offline Wiki Application
Copyright ( C ) 2012 gnosygnu @gmail.com
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation , either version 3 of the
License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
package gplx.gfui ;
2015-02-01 20:11:16 +00:00
import gplx.core.primitives.* ;
2015-05-04 02:30:22 +00:00
import gplx.core.threads.Thread_adp_ ;
2014-07-14 03:23:30 +00:00
import java.security.acl.Owner ;
2015-01-26 01:56:50 +00:00
import gplx.* ;
import org.eclipse.swt.SWT ;
import org.eclipse.swt.browser.* ;
import org.eclipse.swt.events.* ;
import org.eclipse.swt.graphics.* ;
import org.eclipse.swt.widgets.* ;
import java.security.acl.Owner ;
2014-07-14 03:23:30 +00:00
2014-06-30 04:04:32 +00:00
import org.eclipse.swt.SWT ;
import org.eclipse.swt.browser.* ;
import org.eclipse.swt.events.* ;
import org.eclipse.swt.graphics.* ;
import org.eclipse.swt.widgets.* ;
class Swt_html implements Gxw_html , Swt_control , FocusListener {
private Swt_html_lnr_location lnr_location ; private Swt_html_lnr_status lnr_status ;
public Swt_html ( Swt_kit kit , Swt_control owner_control , KeyValHash ctorArgs ) {
this . kit = kit ;
lnr_location = new Swt_html_lnr_location ( this ) ;
lnr_status = new Swt_html_lnr_status ( this ) ;
2015-06-15 01:52:10 +00:00
Object browser_tid_obj = ctorArgs . FetchValOr ( Swt_kit . Cfg_Html_BrowserType , null ) ;
this . browser_tid = browser_tid_obj = = null ? Browser_tid_none : Int_ . cast_ ( browser_tid_obj ) ;
browser = new Browser ( owner_control . Under_composite ( ) , browser_tid ) ;
2014-06-30 04:04:32 +00:00
core = new Swt_core_cmds_html ( this , browser ) ;
browser . addKeyListener ( new Swt_lnr_key ( this ) ) ;
browser . addMouseListener ( new Swt_html_lnr_mouse ( this , browser , kit ) ) ;
browser . addLocationListener ( lnr_location ) ;
browser . addProgressListener ( new Swt_html_lnr_progress ( this ) ) ;
browser . addStatusTextListener ( lnr_status ) ;
browser . addFocusListener ( this ) ;
browser . addTitleListener ( new Swt_html_lnr_title ( this ) ) ;
2014-07-14 03:23:30 +00:00
// browser.addTraverseListener(new Swt_html_lnr_Traverse(this));
2014-06-30 04:04:32 +00:00
}
public Swt_kit Kit ( ) { return kit ; } private Swt_kit kit ;
@Override public Control Under_control ( ) { return browser ; } private Browser browser ;
@Override public Composite Under_composite ( ) { return null ; }
@Override public Control Under_menu_control ( ) { return browser ; }
2015-06-15 01:52:10 +00:00
public int Browser_tid ( ) { return browser_tid ; } private final int browser_tid ;
2014-07-14 03:23:30 +00:00
public void Html_doc_html_load_by_mem ( String html ) {
html_doc_html_load_tid = Gxw_html_load_tid_ . Tid_mem ;
2015-05-25 02:43:55 +00:00
browser . setText ( html ) ; // DBG: Io_mgr.I.SaveFilStr(Io_url_.new_fil_("C:\\temp.txt"), s)
2014-07-14 03:23:30 +00:00
}
public void Html_doc_html_load_by_url ( String path , String html ) {
html_doc_html_load_tid = Gxw_html_load_tid_ . Tid_url ;
2015-05-25 02:43:55 +00:00
Io_mgr . I . SaveFilStr ( path , html ) ;
2014-07-14 03:23:30 +00:00
browser . setUrl ( path ) ;
}
public byte Html_doc_html_load_tid ( ) { return html_doc_html_load_tid ; } private byte html_doc_html_load_tid ;
public void Html_doc_html_load_tid_ ( byte v ) { html_doc_html_load_tid = v ; }
2014-06-30 04:04:32 +00:00
public void Html_js_enabled_ ( boolean v ) { browser . setJavascriptEnabled ( v ) ; }
public void Html_js_cbks_add ( String func_name , GfoInvkAble invk ) { new Swt_html_func ( browser , func_name , invk ) ; }
public String Html_js_eval_script ( String script ) { return Eval_script_as_str ( script ) ; }
2015-06-29 03:29:30 +00:00
public boolean Html_js_eval_proc_as_bool ( String proc , Object . . . args ) { return Bool_ . cast_ ( Html_js_eval_proc_as_obj ( proc , args ) ) ; }
public String Html_js_eval_proc_as_str ( String proc , Object . . . args ) { return Object_ . Xto_str_strict_or_null ( Html_js_eval_proc_as_obj ( proc , args ) ) ; }
private Object Html_js_eval_proc_as_obj ( String proc , Object . . . args ) {
Bry_bfr bfr = Bry_bfr . new_ ( ) ;
bfr . Add_str_a7 ( " return " ) . Add_str_u8 ( proc ) . Add_byte ( Byte_ascii . Paren_bgn ) ;
int args_len = args . length ;
for ( int i = 0 ; i < args_len ; + + i ) {
Object arg = args [ i ] ;
if ( i ! = 0 ) bfr . Add_byte ( Byte_ascii . Comma ) ;
boolean quote_val = true ;
if ( ClassAdp_ . Eq_typeSafe ( arg , Bool_ . Cls_ref_type )
| | ClassAdp_ . Eq_typeSafe ( arg , Int_ . Cls_ref_type )
| | ClassAdp_ . Eq_typeSafe ( arg , Long_ . Cls_ref_type )
) {
quote_val = false ;
}
if ( quote_val ) bfr . Add_byte ( Byte_ascii . Apos ) ;
if ( quote_val )
bfr . Add_str_u8 ( Escape_quote ( Object_ . Xto_str_strict_or_null_mark ( arg ) ) ) ;
else
bfr . Add_obj_strict ( arg ) ;
if ( quote_val ) bfr . Add_byte ( Byte_ascii . Apos ) ;
2014-09-15 03:39:47 +00:00
}
2015-06-29 03:29:30 +00:00
bfr . Add_byte ( Byte_ascii . Paren_end ) . Add_byte ( Byte_ascii . Semic ) ;
return Eval_script ( bfr . Xto_str_and_clear ( ) ) ;
2014-06-30 04:04:32 +00:00
}
2015-06-29 03:29:30 +00:00
private static String Escape_quote ( String v ) {
String rv = v ;
rv = String_ . Replace ( rv , " ' " , " \\ ' " ) ;
rv = String_ . Replace ( rv , " \" " , " \\ \" " ) ;
rv = String_ . Replace ( rv , " \ n " , " \\ n " ) ;
return rv ;
2015-06-15 01:52:10 +00:00
}
2014-06-30 04:04:32 +00:00
public void Html_invk_src_ ( GfoEvObj invk ) { lnr_location . Host_set ( invk ) ; lnr_status . Host_set ( invk ) ; }
2014-07-14 03:23:30 +00:00
public void Html_dispose ( ) {
browser . dispose ( ) ;
delete_owner . SubElems ( ) . DelOrFail ( delete_cur ) ; // NOTE: must delete cur from owner, else new tab will fail after closing one; DATE:2014-07-09
Env_ . GarbageCollect ( ) ;
}
private GfuiElem delete_owner , delete_cur ;
public void Delete_elems_ ( GfuiElem delete_owner , GfuiElem delete_cur ) { this . delete_owner = delete_owner ; this . delete_cur = delete_cur ; } // HACK: set owner / cur so delete can work;
2014-06-30 04:04:32 +00:00
@Override public GxwCore_base Core ( ) { return core ; } private GxwCore_base core ;
@Override public GxwCbkHost Host ( ) { return host ; } @Override public void Host_set ( GxwCbkHost host ) { this . host = host ; } GxwCbkHost host ;
@Override public String TextVal ( ) { return browser . getText ( ) ; }
@Override public void TextVal_set ( String v ) { browser . setText ( v ) ; }
@Override public void EnableDoubleBuffering ( ) { }
@Override public Object Invk ( GfsCtx ctx , int ikey , String k , GfoMsg m ) { return GfoInvkAble_ . Rv_unhandled ; }
private String Eval_script_as_str ( String script ) { return ( String ) Eval_script ( script ) ; }
public Object Eval_script ( String script ) {
eval_rslt . Clear ( ) ;
2014-08-18 03:27:07 +00:00
try {
2014-06-30 04:04:32 +00:00
eval_rslt . Result_set ( browser . evaluate ( script ) ) ;
return eval_rslt . Result ( ) ;
}
catch ( Exception e ) { eval_rslt . Error_set ( e . getMessage ( ) ) ; return eval_rslt . Error ( ) ; }
} private Swt_html_eval_rslt eval_rslt = new Swt_html_eval_rslt ( ) ;
2015-01-26 01:56:50 +00:00
@Override public void focusGained ( FocusEvent arg0 ) { }
@Override public void focusLost ( FocusEvent arg0 ) { }
2014-06-30 04:04:32 +00:00
public static final int
Browser_tid_none = SWT . NONE
, Browser_tid_mozilla = SWT . MOZILLA
2015-05-25 02:43:55 +00:00
, Browser_tid_webkit = SWT . WEBKIT
2014-06-30 04:04:32 +00:00
;
}
class Swt_core_cmds_html extends Swt_core_cmds {
2015-01-26 01:56:50 +00:00
public Swt_core_cmds_html ( Swt_html html_box , Control control ) { super ( control ) ; }
2014-06-30 04:04:32 +00:00
@Override public void Focus ( ) {
if ( Focus_able ( ) )
control . forceFocus ( ) ;
}
@Override public void Select_exec ( ) {
this . Focus ( ) ;
}
}
class Swt_html_eval_rslt {
public void Clear ( ) { error = null ; result = null ; }
public boolean Result_pass ( ) { return error = = null ; }
2015-01-26 01:56:50 +00:00
public Object Result ( ) { return result ; } public void Result_set ( Object v ) { result = v ; error = null ; } private Object result ;
public String Error ( ) { return error ; } public void Error_set ( String v ) { error = v ; result = null ; } private String error ;
2014-06-30 04:04:32 +00:00
}
2015-06-15 01:52:10 +00:00
class Swt_html_lnr_traverse implements TraverseListener {
public Swt_html_lnr_traverse ( Swt_html html_box ) { }
2014-06-30 04:04:32 +00:00
@Override public void keyTraversed ( TraverseEvent arg0 ) { }
}
class Swt_html_lnr_title implements TitleListener {
2015-01-26 01:56:50 +00:00
private Swt_html html_box ;
public Swt_html_lnr_title ( Swt_html html_box ) { this . html_box = html_box ; }
2014-06-30 04:04:32 +00:00
@Override public void changed ( TitleEvent ev ) {
try { UsrDlg_ . _ . Note ( ev . title ) ; }
catch ( Exception e ) { html_box . Kit ( ) . Ask_ok ( " xowa.swt.html_box " , " title.fail " , Err_ . Message_gplx_brief ( e ) ) ; } // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_func extends BrowserFunction {
2015-01-26 01:56:50 +00:00
private GfoInvkAble invk ;
2014-06-30 04:04:32 +00:00
public Swt_html_func ( Browser browser , String name , GfoInvkAble invk ) {
super ( browser , name ) ;
this . invk = invk ;
2015-01-26 01:56:50 +00:00
}
2014-06-30 04:04:32 +00:00
public Object function ( Object [ ] args ) {
try {
return gplx . gfui . Gfui_html . Js_args_exec ( invk , args ) ;
}
catch ( Exception e ) {
return Err_ . Message_gplx_brief ( e ) ;
}
}
}
class Swt_html_lnr_status implements StatusTextListener {
2015-01-26 01:56:50 +00:00
public Swt_html_lnr_status ( Swt_html html_box ) { this . html_box = html_box ; } private Swt_html html_box ;
2014-06-30 04:04:32 +00:00
public void Host_set ( GfoEvObj host ) { this . host = host ; } GfoEvObj host ;
@Override public void changed ( StatusTextEvent ev ) {
2015-04-19 16:33:25 +00:00
if ( html_box . Kit ( ) . Kit_mode__term ( ) )
2014-06-30 04:04:32 +00:00
return ; // shutting down raises status changed events; ignore, else SWT exception thrown; DATE:2014-05-29
String ev_text = ev . text ;
// if (String_.Has(ev_text, "Loading [MathJax]")) return; // suppress MathJax messages; // NOTE: disabled for 2.1 (which no longer outputs messages to status); DATE:2013-05-03
try { if ( host ! = null ) GfoEvMgr_ . PubObj ( host , Gfui_html . Evt_link_hover , " v " , ev_text ) ; }
catch ( Exception e ) { html_box . Kit ( ) . Ask_ok ( " xowa.gui.html_box " , " status.fail " , Err_ . Message_gplx_brief ( e ) ) ; } // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_progress implements ProgressListener {
2015-01-26 01:56:50 +00:00
public Swt_html_lnr_progress ( Swt_html html_box ) { }
2014-06-30 04:04:32 +00:00
@Override public void changed ( ProgressEvent arg0 ) { }
@Override public void completed ( ProgressEvent arg0 ) {
// UsrDlg_._.Note("done");
}
}
class Swt_html_lnr_location implements LocationListener {
2015-01-26 01:56:50 +00:00
public Swt_html_lnr_location ( Swt_html html_box ) { this . html_box = html_box ; } private Swt_html html_box ;
public void Host_set ( GfoEvObj host ) { this . host = host ; } private GfoEvObj host ;
2014-06-30 04:04:32 +00:00
@Override public void changed ( LocationEvent arg ) { Pub_evt ( arg , Gfui_html . Evt_location_changed ) ; }
@Override public void changing ( LocationEvent arg ) { Pub_evt ( arg , Gfui_html . Evt_location_changing ) ; }
2015-01-26 01:56:50 +00:00
private void Pub_evt ( LocationEvent arg , String evt ) {
2014-06-30 04:04:32 +00:00
String location = arg . location ;
if ( String_ . Eq ( location , " about:blank " ) ) return ; // location changing event fires once when page is loaded; ignore
2015-06-15 01:52:10 +00:00
if ( html_box . Browser_tid ( ) = = Swt_html . Browser_tid_webkit // webkit prefixes "about:blank" to anchors; causes TOC to fail when clicking on links; EX:about:blank#TOC1; DATE:2015-06-09
2015-06-22 03:25:42 +00:00
& & String_ . Has_at_bgn ( location , " about:blank " ) ) {
2015-06-15 01:52:10 +00:00
location = String_ . Mid ( location , 11 ) ; // 11 = "about:blank".length
}
2014-07-14 03:23:30 +00:00
if ( html_box . Html_doc_html_load_tid ( ) = = Gxw_html_load_tid_ . Tid_url // navigating to file://page.html will fire location event; ignore if url mode
2015-06-22 03:25:42 +00:00
& & String_ . Has_at_bgn ( location , " file: " )
& & String_ . Has_at_end ( location , " .html " )
2014-08-11 03:10:23 +00:00
)
2014-07-14 03:23:30 +00:00
return ;
2014-06-30 04:04:32 +00:00
try {
GfoEvMgr_ . PubObj ( host , evt , " v " , location ) ;
arg . doit = false ; // cancel navigation event, else there will be an error when trying to go to invalid location
}
catch ( Exception e ) { html_box . Kit ( ) . Ask_ok ( " xowa.gui.html_box " , evt , Err_ . Message_gplx_brief ( e ) ) ; } // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_mouse implements MouseListener {
2015-01-26 01:56:50 +00:00
private GxwElem elem ; private Browser browser ; private Swt_kit kit ;
public Swt_html_lnr_mouse ( GxwElem elem , Browser browser , Swt_kit kit ) { this . elem = elem ; this . browser = browser ; this . kit = kit ; }
2014-06-30 04:04:32 +00:00
@Override public void mouseDown ( MouseEvent ev ) {
if ( Is_at_scrollbar_area ( ) ) return ;
elem . Host ( ) . MouseDownCbk ( XtoMouseData ( ev ) ) ;
}
@Override public void mouseUp ( MouseEvent ev ) {
if ( Is_at_scrollbar_area ( ) ) return ;
elem . Host ( ) . MouseUpCbk ( XtoMouseData ( ev ) ) ;
}
2015-01-26 01:56:50 +00:00
private boolean Is_at_scrollbar_area ( ) {
2014-06-30 04:04:32 +00:00
// WORKAROUND.SWT: SEE:NOTE_1:browser scrollbar and click
Point browser_size = browser . getSize ( ) ;
Point click_pos = kit . Swt_display ( ) . getCursorLocation ( ) ;
return click_pos . x > = browser_size . x - 12 ;
}
@Override public void mouseDoubleClick ( MouseEvent ev ) { }
IptEvtDataMouse XtoMouseData ( MouseEvent ev ) {
IptMouseBtn btn = null ;
switch ( ev . button ) {
case 1 : btn = IptMouseBtn_ . Left ; break ;
case 2 : btn = IptMouseBtn_ . Middle ; break ;
case 3 : btn = IptMouseBtn_ . Right ; break ;
case 4 : btn = IptMouseBtn_ . X1 ; break ;
case 5 : btn = IptMouseBtn_ . X2 ; break ;
}
return IptEvtDataMouse . new_ ( btn , IptMouseWheel_ . None , ev . x , ev . y ) ;
}
}
/ *
NOTE_1 : browser scrollbar and click
a click in the scrollbar area will raise a mouse - down / mouse - up event in content - editable mode
. a click should be consumed by the scrollbar and not have any effect elsewhere on the window
. instead , a click event is raised , and counted twice
1 ) for the scroll bar this will scroll the area .
2 ) for the window . if keyboard - focus is set on a link , then it will activate the link .
swt does not expose any scrollbar information ( visible , width ) , b / c the scrollbar is controlled by the underlying browser
so , assume :
. scrollbar is always present
. scrollbar has arbitrary width ( currently 12 )
. and discard if click is in this scrollbar area
two issues still occur with the workaround
1 ) even if the scrollbar is not present , any click on the right - hand edge of the screen will be ignored
2 ) click - > hold - > move mouse over to left - > release ; the mouse up should be absorbed , but it is not due to position of release
* /