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 ;
import gplx.* ;
2014-09-15 03:39:47 +00:00
import gplx.threads.ThreadAdp_ ;
2014-06-30 04:04:32 +00:00
import org.eclipse.swt.* ;
import org.eclipse.swt.custom.* ;
import org.eclipse.swt.events.* ;
import org.eclipse.swt.graphics.* ;
import org.eclipse.swt.layout.* ;
import org.eclipse.swt.widgets.* ;
public class Swt_tab_mgr implements Gxw_tab_mgr , Swt_control , FocusListener , GfoEvMgrOwner {
2014-09-15 03:39:47 +00:00
private GfuiInvkCmd cmd_sync ;
// private GfuiInvkCmd cmd_async; // NOTE: async needed for some actions like responding to key_down and calling .setSelection; else app hangs; DATE:2014-04-30
2014-06-30 04:04:32 +00:00
public Swt_tab_mgr ( Swt_kit kit , Swt_control owner_control , KeyValHash ctorArgs ) {
this . kit = kit ;
tab_folder = new CTabFolder ( owner_control . Under_composite ( ) , SWT . BORDER ) ;
tab_folder . setBorderVisible ( false ) ;
tab_folder . setLayoutData ( new GridData ( SWT . FILL , SWT . FILL , true , false ) ) ;
tab_folder . setSimple ( true ) ;
tab_folder . addListener ( SWT . Selection , new Swt_tab_mgr_lnr_selection ( this ) ) ;
tab_folder . addKeyListener ( new Swt_lnr_key ( this ) ) ;
new Swt_tab_mgr_lnr_drag_drop ( this , tab_folder ) ;
tab_folder . addCTabFolder2Listener ( new Swt_tab_mgr_lnr_close ( this ) ) ;
core = new Swt_core_cmds ( tab_folder ) ;
2014-09-15 03:39:47 +00:00
// cmd_async = kit.New_cmd_async(this);
cmd_sync = kit . New_cmd_sync ( this ) ;
2014-06-30 04:04:32 +00:00
}
public Swt_kit Kit ( ) { return kit ; } private Swt_kit kit ;
public CTabFolder Under_ctabFolder ( ) { return tab_folder ; }
@Override public Control Under_control ( ) { return tab_folder ; } private CTabFolder tab_folder ;
@Override public Composite Under_composite ( ) { return tab_folder ; }
@Override public Control Under_menu_control ( ) { return tab_folder ; }
public GfoEvMgr EvMgr ( ) { return ev_mgr ; } private GfoEvMgr ev_mgr ;
public void EvMgr_ ( GfoEvMgr v ) { ev_mgr = v ; }
public ColorAdp Btns_selected_color ( ) { return btns_selected_color ; } private ColorAdp btns_selected_color ;
public void Btns_selected_color_ ( ColorAdp v ) {
btns_selected_color = v ;
tab_folder . setSelectionBackground ( kit . New_color ( v ) ) ;
}
public ColorAdp Btns_unselected_color ( ) { return btns_unselected_color ; }
public void Btns_unselected_color_ ( ColorAdp v ) {
btns_unselected_color = v ;
tab_folder . setBackground ( kit . New_color ( v ) ) ;
} private ColorAdp btns_unselected_color ;
@Override public boolean Btns_curved ( ) { return tab_folder . getSimple ( ) ; } @Override public void Btns_curved_ ( boolean v ) { tab_folder . setSimple ( ! v ) ; }
@Override public boolean Btns_place_on_top ( ) { return tab_folder . getTabPosition ( ) = = SWT . TOP ; }
@Override public void Btns_place_on_top_ ( boolean v ) { tab_folder . setTabPosition ( v ? SWT . TOP : SWT . BOTTOM ) ; tab_folder . layout ( ) ; }
@Override public int Btns_height ( ) { return tab_folder . getTabHeight ( ) ; } @Override public void Btns_height_ ( int v ) { tab_folder . setTabHeight ( v ) ; tab_folder . layout ( ) ; }
@Override public boolean Btns_close_visible ( ) { return btns_close_visible ; } private boolean btns_close_visible = true ;
@Override public void Btns_close_visible_ ( boolean v ) {
this . btns_close_visible = v ;
CTabItem [ ] itms = tab_folder . getItems ( ) ;
int len = itms . length ;
for ( int i = 0 ; i < len ; i + + )
itms [ i ] . setShowClose ( v ) ;
}
@Override public boolean Btns_unselected_close_visible ( ) { return tab_folder . getUnselectedCloseVisible ( ) ; } @Override public void Btns_unselected_close_visible_ ( boolean v ) {
tab_folder . setUnselectedCloseVisible ( v ) ; }
@Override public Gxw_tab_itm Tabs_add ( Gfui_tab_itm_data tab_data ) {
Swt_tab_itm rv = new Swt_tab_itm ( this , kit , tab_folder , tab_data ) ;
rv . Under_CTabItem ( ) . setData ( tab_data ) ;
CTabItem ctab_itm = rv . Under_CTabItem ( ) ;
ctab_itm . setShowClose ( btns_close_visible ) ;
return rv ;
}
@Override public void Tabs_close_by_idx ( int i ) {
CTabItem itm = tab_folder . getItems ( ) [ i ] ;
Gfui_tab_itm_data tab_data = Get_tab_data ( itm ) ;
CTabItem next_tab = Tabs_select_after_closing_itm ( tab_data ) ; // NOTE: must calc next_tab before calling Pub_tab_closed; latter will recalc idx
2014-09-15 03:39:47 +00:00
this . Tabs_select_by_itm ( next_tab ) ; // NOTE: select tab before closing; DATE:2014-09-10
Pub_tab_closed ( tab_data . Key ( ) ) ; // NOTE: dispose does not call event for .close; must manually raise event;
2014-09-08 02:38:50 +00:00
itm . dispose ( ) ;
2014-06-30 04:04:32 +00:00
}
@Override public void Tabs_select_by_idx ( int i ) {
if ( i = = Gfui_tab_itm_data . Idx_null ) return ; // 0 tabs; return;
msg_tabs_select_by_idx_swt . Clear ( ) ;
msg_tabs_select_by_idx_swt . Add ( " v " , i ) ;
2014-09-15 03:39:47 +00:00
cmd_sync . Invk ( GfsCtx . _ , 0 , Invk_tabs_select_by_idx_swt , msg_tabs_select_by_idx_swt ) ;
2014-06-30 04:04:32 +00:00
} private GfoMsg msg_tabs_select_by_idx_swt = GfoMsg_ . new_cast_ ( Invk_tabs_select_by_idx_swt ) ;
@Override public void Tabs_switch ( int src , int trg ) { Tabs_switch ( tab_folder . getItem ( src ) , tab_folder . getItem ( trg ) ) ; }
public boolean Tabs_switch ( CTabItem src_tab_itm , CTabItem trg_tab_itm ) {
Control temp_control = src_tab_itm . getControl ( ) ;
src_tab_itm . setControl ( trg_tab_itm . getControl ( ) ) ;
trg_tab_itm . setControl ( temp_control ) ;
String temp_str = src_tab_itm . getText ( ) ;
src_tab_itm . setText ( trg_tab_itm . getText ( ) ) ;
trg_tab_itm . setText ( temp_str ) ;
temp_str = src_tab_itm . getToolTipText ( ) ;
src_tab_itm . setToolTipText ( trg_tab_itm . getToolTipText ( ) ) ;
trg_tab_itm . setToolTipText ( temp_str ) ;
Gfui_tab_itm_data src_tab_data = Get_tab_data ( src_tab_itm ) ;
Gfui_tab_itm_data trg_tab_data = Get_tab_data ( trg_tab_itm ) ;
int src_tab_idx = src_tab_data . Idx ( ) , trg_tab_idx = trg_tab_data . Idx ( ) ;
tab_folder . setSelection ( trg_tab_itm ) ;
GfoEvMgr_ . PubVals ( this , Gfui_tab_mgr . Evt_tab_switched , KeyVal_ . new_ ( " src " , src_tab_data . Key ( ) ) , KeyVal_ . new_ ( " trg " , trg_tab_data . Key ( ) ) ) ;
return src_tab_idx < trg_tab_idx ;
}
public void Tabs_select_by_itm ( CTabItem itm ) {
if ( itm = = null ) return ; // 0 tabs; return;
msg_tabs_select_by_itm_swt . Clear ( ) ;
msg_tabs_select_by_itm_swt . Add ( " v " , itm ) ;
2014-09-15 03:39:47 +00:00
cmd_sync . Invk ( GfsCtx . _ , 0 , Invk_tabs_select_by_itm_swt , msg_tabs_select_by_itm_swt ) ;
2014-06-30 04:04:32 +00:00
} private GfoMsg msg_tabs_select_by_itm_swt = GfoMsg_ . new_cast_ ( Invk_tabs_select_by_itm_swt ) ;
private void Tabs_select_by_idx_swt ( int idx ) {
tab_folder . setSelection ( idx ) ;
CTabItem itm = tab_folder . getItem ( idx ) ;
Pub_tab_selected ( Get_tab_key ( itm ) ) ; // NOTE: setSelection does not call event for SWT.Selection; must manually raise event;
}
private void Tabs_select_by_itm_swt ( CTabItem itm ) {
tab_folder . setSelection ( itm ) ;
Pub_tab_selected ( Get_tab_key ( itm ) ) ; // NOTE: setSelection does not call event for SWT.Selection; must manually raise event;
}
public CTabItem Tabs_select_after_closing_itm ( Gfui_tab_itm_data tab_data ) {
int next_idx = Gfui_tab_itm_data . Get_idx_after_closing ( tab_data . Idx ( ) , tab_folder . getItemCount ( ) ) ;
return next_idx = = Gfui_tab_itm_data . Idx_null ? null : tab_folder . getItem ( next_idx ) ;
}
public void Pub_tab_selected ( String key ) {
GfoEvMgr_ . PubObj ( this , Gfui_tab_mgr . Evt_tab_selected , " key " , key ) ;
}
public void Pub_tab_closed ( String key ) {
GfoEvMgr_ . PubObj ( this , Gfui_tab_mgr . Evt_tab_closed , " key " , key ) ;
}
@Override public GxwCore_base Core ( ) { return core ; } 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 " not implemented " ; }
@Override public void TextVal_set ( String v ) { }
@Override public void EnableDoubleBuffering ( ) { }
@Override public Object Invk ( GfsCtx ctx , int ikey , String k , GfoMsg m ) {
if ( String_ . Eq ( k , Invk_tabs_select_by_idx_swt ) ) Tabs_select_by_idx_swt ( m . ReadInt ( " v " ) ) ;
else if ( String_ . Eq ( k , Invk_tabs_select_by_itm_swt ) ) Tabs_select_by_itm_swt ( ( CTabItem ) m . ReadObj ( " v " , null ) ) ;
else return GfoInvkAble_ . Rv_unhandled ;
return this ;
}
@Override public void focusGained ( FocusEvent arg0 ) { }
@Override public void focusLost ( FocusEvent arg0 ) { }
private static String
Invk_tabs_select_by_idx_swt = " tabs_select_by_idx "
, Invk_tabs_select_by_itm_swt = " tabs_select_by_itm "
;
public static Gfui_tab_itm_data Get_tab_data_by_obj ( Object data ) { return ( Gfui_tab_itm_data ) data ; }
public static Gfui_tab_itm_data Get_tab_data ( CTabItem itm ) { return ( Gfui_tab_itm_data ) itm . getData ( ) ; }
public static String Get_tab_key ( CTabItem itm ) { return ( ( Gfui_tab_itm_data ) itm . getData ( ) ) . Key ( ) ; }
}
class Swt_tab_mgr_lnr_selection implements Listener {
public Swt_tab_mgr_lnr_selection ( Swt_tab_mgr tab_folder ) { this . tab_folder = tab_folder ; } private Swt_tab_mgr tab_folder ;
public void handleEvent ( Event ev ) {
tab_folder . Pub_tab_selected ( Swt_tab_mgr . Get_tab_data_by_obj ( ev . item . getData ( ) ) . Key ( ) ) ;
}
}
class Swt_tab_mgr_lnr_close extends CTabFolder2Adapter { // handles close when tab x is clicked
public Swt_tab_mgr_lnr_close ( Swt_tab_mgr tab_folder ) { this . tab_folder = tab_folder ; } private Swt_tab_mgr tab_folder ;
@Override public void close ( CTabFolderEvent ev ) {
Gfui_tab_itm_data tab_data = Swt_tab_mgr . Get_tab_data_by_obj ( ev . item . getData ( ) ) ;
tab_folder . Tabs_close_by_idx ( tab_data . Idx ( ) ) ;
ev . doit = false ; // mark ev handled, since Tabs_close_by_idx closes tab
}
}
class Swt_tab_mgr_lnr_drag_drop implements Listener {
private boolean dragging = false ;
private boolean drag_stop = false ;
private CTabItem drag_itm ;
private final Swt_tab_mgr tab_mgr ; private final CTabFolder tab_folder ; private final Display display ;
private Point prv_mouse ;
private Point dead_zone = null ;
public Swt_tab_mgr_lnr_drag_drop ( Swt_tab_mgr tab_mgr , CTabFolder tab_folder ) {
this . tab_mgr = tab_mgr ; this . tab_folder = tab_folder ; this . display = tab_folder . getDisplay ( ) ;
tab_folder . addListener ( SWT . DragDetect , this ) ;
tab_folder . addListener ( SWT . MouseUp , this ) ;
tab_folder . addListener ( SWT . MouseMove , this ) ;
tab_folder . addListener ( SWT . MouseExit , this ) ;
tab_folder . addListener ( SWT . MouseEnter , this ) ;
}
private void Drag_drop_bgn ( CTabItem itm ) {
dragging = true ;
drag_stop = false ;
drag_itm = itm ;
dead_zone = null ;
}
private void Drag_drop_end ( ) {
tab_folder . setInsertMark ( null , false ) ;
dragging = false ;
drag_stop = false ;
drag_itm = null ;
}
public void handleEvent ( Event e ) {
Point cur_mouse = e . type = = SWT . DragDetect
? tab_folder . toControl ( display . getCursorLocation ( ) ) //see bug 43251
: new Point ( e . x , e . y )
;
switch ( e . type ) {
case SWT . DragDetect : {
CTabItem itm = tab_folder . getItem ( cur_mouse ) ;
if ( itm = = null ) return ;
this . Drag_drop_bgn ( itm ) ;
break ;
}
case SWT . MouseEnter :
if ( drag_stop ) {
dragging = e . button ! = 0 ;
drag_stop = false ;
}
break ;
case SWT . MouseExit :
if ( dragging )
Drag_drop_end ( ) ;
break ;
case SWT . MouseUp : {
if ( ! dragging ) return ;
Drag_drop_end ( ) ;
break ;
}
case SWT . MouseMove : {
if ( ! dragging ) return ;
CTabItem curr_itm = tab_folder . getItem ( cur_mouse ) ;
if ( curr_itm = = null ) {
tab_folder . setInsertMark ( null , false ) ;
return ;
}
if ( curr_itm = = drag_itm ) return ; // curr_itm is same as drag_itm; ignore
int cur_mouse_x = cur_mouse . x ;
int prv_mouse_x = prv_mouse = = null ? 0 : prv_mouse . x ;
prv_mouse = cur_mouse ; // set prv_mouse now b/c of early return below; note that cur_mouse_x and prv_mouse_x are cached above
if ( dead_zone ! = null // dead_zone exists
& & Int_ . Between ( cur_mouse_x , dead_zone . x , dead_zone . y ) ) { // mouse is in dead_zone
int drag_idx = Swt_tab_mgr . Get_tab_data ( drag_itm ) . Idx ( ) ;
int curr_idx = Swt_tab_mgr . Get_tab_data ( curr_itm ) . Idx ( ) ;
if ( drag_idx > curr_idx & & cur_mouse_x < prv_mouse_x ) { } // drag_itm is right of curr_itm, but mouse is moving left (direction reversed); cancel
else if ( drag_idx < curr_idx & & cur_mouse_x > prv_mouse_x ) { } // drag_itm is left of curr_itm, but mouse is moving right (direction reversed); cancel
else
return ; // in dead zone, and still moving in original direction; return early
}
boolean fwd = tab_mgr . Tabs_switch ( drag_itm , curr_itm ) ;
drag_itm = curr_itm ;
Rectangle drag_rect = drag_itm . getBounds ( ) ;
dead_zone = Calc_dead_zone ( fwd , cur_mouse_x , drag_rect . x , drag_rect . width ) ;
break ;
}
}
}
public static Point Calc_dead_zone ( boolean fwd , int mouse_x , int drag_l , int drag_w ) {
if ( fwd ) { // drag_itm was moving fwd (moving right)
if ( mouse_x < drag_l ) return new Point ( mouse_x , drag_l ) ; // mouse_x < drag_l; create dead_zone until mouse_x reaches drag_l; occurs when moving drag is small_title and trg_itm is large_title
}
else { // drag_itm was moving bwd (moving left)
int drag_r = drag_l + drag_w ;
if ( mouse_x > drag_r ) return new Point ( drag_r , mouse_x ) ; // mouse_x > drag_r; create dead_zone until mouse_x reaches drag_r
}
return null ;
}
}
//#}