/* * File : ActiveBagContentPreviewPanel.java * Created : 10-oct-2002 10:57 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2005 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details (see the LICENSE file). */ package edu.xtec.jclic.boxes; import edu.xtec.jclic.Activity; import edu.xtec.jclic.Constants; import edu.xtec.jclic.activities.textGrid.CrossWord; import edu.xtec.jclic.bags.MediaBagEditor; import edu.xtec.util.ResizerPanel; import java.awt.AWTEvent; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; /** * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.09.09 */ public class ActiveBagContentPreviewPanel extends ResizerPanel implements FocusListener { public static final int MARGIN=10; AbstractBox[] bg=new AbstractBox[2]; ActiveBoxBag[] abg=new ActiveBoxBag[2]; TextGrid[] grid=new TextGrid[2]; ActiveBagContent[] abc=new ActiveBagContent[2]; ActiveBagContent[] altAbc=new ActiveBagContent[2]; ActiveBagContent[][] allAbc=new ActiveBagContent[][]{abc, altAbc}; TextGridContent[] tgc=new TextGridContent[2]; MediaBagEditor mbe; boolean[] allowResize=new boolean[2]; boolean dragCursorX=false, dragCursorY=false; boolean dragging=false; int margin=MARGIN; private int cgrid=0; int boxGridPos=Activity.AB; ActiveBagContentEditor parent; int editMode; int currentLine, highlightLine; BoxConnector bc; boolean showAllArrows=true; boolean crossWord=false; ActiveBox hClue, vClue; Color softLineColor=Color.blue; Color activeLineColor=Color.red; Color arrowColor=BoxConnector.DEFAULT_XOR_COLOR; public static final int EDIT_GRIDS=0, EDIT_LINKS=1, EDIT_BOOL=2; public static final float ARROW_WIDTH=2.0F; /** Creates a new instance of ActiveBagContentPreviewPanel */ public ActiveBagContentPreviewPanel(ActiveBagContentEditor parent, boolean isCrossWord) { this.parent=parent; crossWord=isCrossWord; bc=new BoxConnector(this); bc.arrow=true; bc.line_width=ARROW_WIDTH; bc.lineColor=activeLineColor; currentLine=-1; highlightLine=-1; editMode=EDIT_GRIDS; enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.KEY_EVENT_MASK); addFocusListener(this); } /* * ATENCIO: DEPRECATED A Java 1.4!! * public boolean isFocusTraversable(){ if(grid[0]!=null || grid[1]!=null) return true; return super.isFocusTraversable(); } */ public AbstractBox getAbstractBox(int index){ return bg[index]; } public boolean isCrossWord(){ return crossWord; } public void setActiveBagContent(int index, ActiveBagContent abcx, ActiveBagContent altAbcx, TextGridContent tgcx){ abc[index]=abcx; altAbc[index]=altAbcx; tgc[index]=tgcx; bg[index]=null; grid[index]=null; abg[index]=null; if(tgc[index]!=null){ grid[index]=TextGrid.createEmptyGrid(null, this, margin, margin, tgc[index], false); bg[index]=grid[index]; grid[index].setChars(tgc[index].text); if(crossWord) grid[index].setCellAttributes(true, false); grid[index].setCursorAt(0, 0, false); grid[index].setCursorEnabled(true); checkCursor(false); allowResize[index]=true; } else if(crossWord && index==1 && abc[index]!=null && altAbc[index]!=null){ abg[1]=new ActiveBoxBag(null, this, abc[1].bb); bg[1]=abg[1]; ActiveBox ab=new ActiveBox(abg[1], this, null); ActiveBoxContent abct=new ActiveBoxContent(); abct.setImgContent(edu.xtec.util.ResourceManager.getImageIcon("buttons/textright.png").getImage(), null); ab.setContent(abct); abg[1].addActiveBox(ab); hClue=new ActiveBox(abg[1], this, null); abg[1].addActiveBox(hClue); ab=new ActiveBox(abg[1], this, null); abct=new ActiveBoxContent(); abct.setImgContent(edu.xtec.util.ResourceManager.getImageIcon("buttons/textdown.png").getImage(), null); ab.setContent(abct); abg[1].addActiveBox(ab); vClue=new ActiveBox(abg[1], this, null); abg[1].addActiveBox(vClue); abg[1].setBorder(true); resizeCrossWordPanel((int)abc[1].w, (int)abc[1].h); cursorPosChanged(); allowResize[1]=true; } else if(abc[index]!=null){ abg[index]=ActiveBoxGrid.createEmptyGrid(null, this, margin, margin, abc[index]); bg[index]=abg[index]; abg[index].setContent(abc[index], altAbc[index]); allowResize[index]=(abc[index].img==null); } if(bg[index]!=null) bg[index].setVisible(true); /* if(index==0 && bg[index]!=null && abcx!=null){ activeLineColor=bg[index].getBoxBaseResolve().textColor; bc.lineColor=activeLineColor; } */ if(bc.active) bc.end(); currentLine=-1; highlightLine=-1; dragCursorX=false; dragCursorY=false; setCursor(null); revalidate(); BoxBase.resetAllFonts(); repaint(); } protected void resizeCrossWordPanel(int w, int h){ if(crossWord && abg[1]!=null && abg[1].getNumCells()==4){ boolean rowDist=(boxGridPos==Activity.AUB || boxGridPos==Activity.BUA); int x=(int)(abg[1].getX()); int y=(int)(abg[1].getY()); ActiveBox ab=abg[1].getActiveBox(0); ab.setBounds(x, y, CrossWord.LABEL_WIDTH, h); ab=abg[1].getActiveBox(1); ab.setBounds(x+CrossWord.LABEL_WIDTH, y, w, h); int x0 = rowDist ? x+CrossWord.LABEL_WIDTH+w : x; int y0 = rowDist ? y : y+h; ab=abg[1].getActiveBox(2); ab.setBounds(x0, y0, CrossWord.LABEL_WIDTH, h); ab=abg[1].getActiveBox(3); ab.setBounds(x0+CrossWord.LABEL_WIDTH, y0, w, h); abg[1].recalcSize(); /* abg[1].width = rowDist ? (2*CrossWord.LABEL_WIDTH)+2*w : CrossWord.LABEL_WIDTH+w; abg[1].height = rowDist ? h : 2*h; */ } } @Override public void doLayout(){ if(bg[0]!=null){ if(bg[1]!=null) BoxBag.layoutDouble(getSize(), (Resizable)bg[0], (Resizable)bg[1], boxGridPos, margin); else BoxBag.layoutSingle(getSize(), (Resizable)bg[0], margin); } } @Override public void paintComponent(Graphics g){ super.paintComponent(g); if(bg[0]!=null){ Graphics2D g2=(Graphics2D)g; RenderingHints rh=g2.getRenderingHints(); g2.setRenderingHints(Constants.DEFAULT_RENDERING_HINTS); while(true){ BoxBase.flagFontReduced=false; for(int i=0; i<2; i++) if(bg[i]!=null) bg[i].update(g2, g2.getClipBounds(), this); if(!BoxBase.flagFontReduced) break; } if(editMode==EDIT_LINKS && abg[1]!=null && abc[0]!=null){ for(int i=0; i<abc[0].getNumCells(); i++){ if(showAllArrows && i!=currentLine && i!=highlightLine) drawArrow(g2, i); } if(highlightLine>=0) drawArrow(g2, highlightLine); bc.update(g2, g2.getClipBounds(), this); } g2.setRenderingHints(rh); } } private void drawArrow(Graphics2D g2, int i){ if(abg[0]==null || abg[1]==null) return; ActiveBox bx=abg[0].getActiveBox(i); int id=abc[0].getActiveBoxContent(i).id; if(id>=0 && id<abc[1].getNumCells()){ ActiveBox bx2=abg[1].getActiveBox(id); if(bx!=null && bx2!=null){ BoxConnector.drawLine(g2 , new Point2D.Double(bx.getX()+bx.getWidth()/2, bx.getY()+bx.getHeight()/2) , new Point2D.Double(bx2.getX()+bx2.getWidth()/2, bx2.getY()+bx2.getHeight()/2) , true , (i==highlightLine ? activeLineColor : softLineColor) , arrowColor , BoxConnector.ARROW_L , BoxConnector.ARROW_ANGLE , (i==highlightLine ? ARROW_WIDTH : BoxConnector.LINE_WIDTH) ); } } } public void setMediaBagEditor(MediaBagEditor mbe){ this.mbe=mbe; } @Override protected void processEvent(AWTEvent e){ boolean consumed=false; if(bg[0]!=null){ if(e instanceof MouseEvent){ switch(editMode){ case EDIT_GRIDS: consumed=processMouseGrids((MouseEvent)e); break; case EDIT_LINKS: consumed=processMouseLinks((MouseEvent)e); break; case EDIT_BOOL: consumed=processMouseBool((MouseEvent)e); break; } } else if(e instanceof KeyEvent && (grid[0]!=null || grid[1]!=null)) consumed=processKey((KeyEvent)e); } if(!consumed) super.processEvent(e); } private boolean processMouseGrids(MouseEvent ev){ boolean consumed=false; Point p=ev.getPoint(); int id=ev.getID(); int index=cgrid; if(!dragging && (id==MouseEvent.MOUSE_MOVED || id==MouseEvent.MOUSE_PRESSED)){ if(bg[0]!=null && bg[0].contains(p)) index=0; else if(bg[1]!=null && bg[1].contains(p)) index=1; else index=-1; } AbstractBox xbox = index>=0 ? bg[index] : null; ActiveBoxBag xbg = (abg[0]==xbox ? abg[0] : (abg[1]==xbox ? abg[1] : null)); TextGrid xgrid = (grid[0]==xbox ? grid[0] : (grid[1]==xbox ? grid[1] : null)); switch(ev.getID()){ case MouseEvent.MOUSE_MOVED: if(!dragging){ Cursor newCursor=null; if(xbox!=null && allowResize[index]){ dragCursorX=Math.abs(p.x-xbox.x-xbox.width)<5 && p.y>=xbox.y && p.y<(xbox.y+xbox.height+5); dragCursorY=Math.abs(p.y-xbox.y-xbox.height)<5 && p.x>=xbox.x && p.x<(xbox.x+xbox.width+5); if(dragCursorX && dragCursorY) newCursor=Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR); else if(dragCursorY) newCursor=Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR); else if(dragCursorX) newCursor=Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR); } if(newCursor==null && xbg!=null && xbg.findActiveBox(p)!=null) newCursor=Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); setCursor(newCursor); } break; case MouseEvent.MOUSE_PRESSED: if(xbox!=null){ setPanelSelected(index); if(dragCursorX || dragCursorY){ dragging=true; resizeByDrag(p, false); } else if(xgrid!=null){ if(xgrid.contains(p)){ Point pt=xgrid.getLogicalCoords(p); if(pt!=null){ setCursorAt(pt.x, pt.y); } } } consumed=true; } break; case MouseEvent.MOUSE_RELEASED: if(xbox!=null){ if(dragging){ resizeByDrag(p, true); dragging=false; } else if(xbg!=null){ ActiveBox ab=xbg.findActiveBox(p); if(ab!=null){ ActiveBoxContent abxcnt=ab.getCurrentContent(); int group=-1; int bag=-1; int item=-1; for(int i=0; i<allAbc.length && item<0; i++){ for(int j=0; j<allAbc[i].length && item<0; j++){ if(allAbc[i][j]!=null){ item=allAbc[i][j].indexOf(abxcnt); if(item>=0){ bag=j; group=i; } } } } if(item>=0){ ActiveBoxContent abxc=ActiveBoxContentEditor.getActiveBoxContent( abxcnt, this, parent.getOptions(), mbe, ab); if(abxc!=null){ allAbc[group][bag].setActiveBoxContentAt(abxc, item); setModified(true); if(!ab.isAlternative()){ ab.setContent(abxc); } else{ ab.setAltContent(abxc); } //ab.setAlternative(alt); BoxBase.resetAllFonts(); repaint(); } } } } consumed=true; } break; case MouseEvent.MOUSE_DRAGGED: if(xbox!=null && dragging){ resizeByDrag(p, false); consumed=true; } break; } return consumed; } protected boolean processMouseLinks(MouseEvent ev){ boolean consumed=false; if(abg[0]!=null && abg[1]!=null){ Point pt=ev.getPoint(); switch(ev.getID()){ case MouseEvent.MOUSE_DRAGGED: case MouseEvent.MOUSE_MOVED: if(bc.active) bc.moveTo(pt); else{ int newLine=-1; ActiveBox bx=abg[0].findActiveBox(pt); if(bx!=null){ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); newLine=bx.idOrder; } else setCursor(null); if(newLine!=highlightLine){ highlightLine=newLine; repaint(); } } consumed=true; break; case MouseEvent.MOUSE_PRESSED: if(bc.active){ bc.end(); ActiveBox bx=abg[1].findActiveBox(bc.dest); ActiveBoxContent bc0=abc[0].getActiveBoxContent(currentLine); bc0.id=(bx==null ? -1 : bx.idOrder); highlightLine=currentLine; currentLine=-1; setModified(true); repaint(); } else{ ActiveBox bx=abg[0].findActiveBox(pt); if(bx!=null){ highlightLine=-1; currentLine=bx.idOrder; repaint(); bc.begin(pt); } } consumed=true; break; } } return consumed; } private void resizeByDrag(Point p, boolean finish){ if(cgrid>=0 && bg[cgrid]!=null){ int ncw=0, nch=0; if(abg[cgrid]==bg[cgrid] && abc[cgrid]!=null){ if(crossWord){ ncw=1; nch=1; } else{ ncw=abc[cgrid].ncw; nch=abc[cgrid].nch; } } else if(grid[cgrid]==bg[cgrid] && tgc[cgrid]!=null){ ncw=tgc[cgrid].ncw; nch=tgc[cgrid].nch; } if(ncw>0 && nch>0){ int w=(int)(bg[cgrid].width/ncw); int h=(int)(bg[cgrid].height/nch); if(dragCursorX) w=(int)((p.x-bg[cgrid].x)/ncw); if(dragCursorY) h=(int)((p.y-bg[cgrid].y)/nch); if(crossWord && cgrid==1){ if(boxGridPos==Activity.AUB || boxGridPos==Activity.BUA){ w=(w-2*40)/2; } else{ w=w-40; h=h/2; } } if(w>10 && h>10){ doResize(cgrid, w, h, finish); if(finish && crossWord) cursorPosChanged(); } } } /* if(cgrid>=0 && bg[cgrid]!=null && ((abc[cgrid]!=null && abc[cgrid].ncw>0 && abc[cgrid].nch>0) || (tgc[cgrid]!=null && tgc[cgrid].ncw>0 && tgc[cgrid].nch>0))){ int ncw = tgc[cgrid]!=null ? tgc[cgrid].ncw : abc[cgrid].ncw; int nch = tgc[cgrid]!=null ? tgc[cgrid].nch : abc[cgrid].nch; int w=(int)(bg[cgrid].width/ncw); int h=(int)(bg[cgrid].height/nch); if(dragCursorX) w=(int)((p.x-bg[cgrid].x)/ncw); if(dragCursorY) h=(int)((p.y-bg[cgrid].y)/nch); if(w>10 && h>10){ doResize(cgrid, w, h, finish); } } */ } protected void doResize(int index, int w, int h, boolean finish){ AbstractBox xbox = (index>=0 ? bg[index] : null); if(xbox!=null){ setModified(true); if(tgc[index]!=null){ tgc[index].w=w; tgc[index].h=h; } else if(abc[index]!=null){ abc[index].w=w; abc[index].h=h; } if(crossWord && index==1){ altAbc[index].w=w; altAbc[index].h=h; resizeCrossWordPanel(w, h); } else{ int ncw = tgc[index]!=null ? tgc[index].ncw : abc[index].ncw; int nch = tgc[index]!=null ? tgc[index].nch : abc[index].nch; Rectangle r=new Rectangle((int)bg[index].getX(), (int)bg[index].getY(), w*ncw, h*nch); xbox.setBounds(r); } if(finish){ /* setActiveBagContent(index, abc[index], altAbc[index], tgc[index]); ActiveBoxBag xbg=(xbox==abg[0] ? abg[0] : (xbox==abg[1] ? abg[1] : null)); if(xbg!=null && xbg.isAlternative()) xbg.setAlternative(true); */ boolean xbgAlt; ActiveBoxBag xbg=(xbox==abg[0] ? abg[0] : (xbox==abg[1] ? abg[1] : null)); xbgAlt = xbg!=null && xbg.isAlternative(); setActiveBagContent(index, abc[index], altAbc[index], tgc[index]); if(xbgAlt && abg[index]!=null) abg[index].setAlternative(true); } parent.resized(index); } repaint(); } protected boolean processMouseBool(MouseEvent ev){ boolean consumed=false; if(abg[0]!=null){ ActiveBox bx=abg[0].findActiveBox(ev.getPoint()); switch(ev.getID()){ case MouseEvent.MOUSE_MOVED: setCursor(bx!=null ? Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : null); consumed=true; break; case MouseEvent.MOUSE_RELEASED: if(bx!=null){ int v=bx.getContent().id; v=v>0 ? 0 : 1; bx.getContent().id=v; bx.setInverted(v>0); bx.setMarked(v>0); setModified(true); consumed=true; } break; } } return consumed; } public void setModified(boolean modified) { parent.setModified(modified); } /** Getter for property boxGridPos. * @return Value of property boxGridPos. */ public int getBoxGridPos() { return boxGridPos; } /** Setter for property boxGridPos. * @param boxGridPos New value of property boxGridPos. */ public void setBoxGridPos(int boxGridPos) { this.boxGridPos = boxGridPos; if(crossWord && abc[1]!=null){ resizeCrossWordPanel((int)abc[1].w, (int)abc[1].h); } BoxBase.resetAllFonts(); revalidate(); } /** Getter for property editMode. * @return Value of property editMode. */ public int getEditMode() { return editMode; } /** Setter for property editMode. * @param editMode New value of property editMode. */ public void setEditMode(int editMode) { boolean checkBool=(editMode==EDIT_BOOL || this.editMode==EDIT_BOOL); this.editMode = editMode; if(checkBool && abg[0]!=null){ for(int i=0; i<abg[0].getNumCells(); i++){ ActiveBox bx=abg[0].getActiveBox(i); if(bx!=null) { bx.setInverted(editMode==EDIT_BOOL ? bx.getContent().id>0 : false); bx.setMarked(editMode==EDIT_BOOL ? bx.getContent().id>0 : false); } } } repaint(); } /** Getter for property showAllArrows. * @return Value of property showAllArrows. */ public boolean isShowAllArrows() { return showAllArrows; } /** Setter for property showAllArrows. * @param showAllArrows New value of property showAllArrows. */ public void setShowAllArrows(boolean showAllArrows) { this.showAllArrows = showAllArrows; repaint(); } protected void moveCursor(int dx, int dy){ if(cgrid>=0 && grid[cgrid]!=null){ grid[cgrid].moveCursor(dx, dy, false); cursorPosChanged(); } } protected void setCursorAt(int x, int y){ if(cgrid>=0 && grid[cgrid]!=null) grid[cgrid].setCursorAt(x, y, false); cursorPosChanged(); } protected void cursorPosChanged(){ if(crossWord && grid[0]!=null && hClue!=null && vClue!=null){ Point pt=grid[0].getCursor(); if(pt!=null){ Point items=grid[0].getItemFor(pt.x, pt.y); if(items!=null){ ActiveBoxContent abxc=abc[1].getActiveBoxContentWith(pt.y, items.x); if(abxc==null){ abc[1].insertActiveBoxContentWith(pt.y, items.x); abxc=abc[1].getActiveBoxContentWith(pt.y, items.x); } hClue.setContent(abxc); abxc=altAbc[1].getActiveBoxContentWith(pt.x, items.y); if(abxc==null){ altAbc[1].insertActiveBoxContentWith(pt.x, items.y); abxc=altAbc[1].getActiveBoxContentWith(pt.x, items.y); } vClue.setContent(abxc); } } } } public boolean processKey(KeyEvent e){ boolean consumed=false; if(cgrid>=0 && grid[cgrid]!=null && tgc[cgrid]!=null){ int dx=0, dy=0; boolean delete=false, moveFirst=false; Point cur=grid[cgrid].getCursor(); char ch1=0; switch(e.getID()){ case KeyEvent.KEY_PRESSED: switch(e.getKeyCode()){ case KeyEvent.VK_RIGHT: dx=1; break; case KeyEvent.VK_LEFT: dx=-1; break; case KeyEvent.VK_DOWN: dy=1; break; case KeyEvent.VK_UP: dy=-1; break; case KeyEvent.VK_BACK_SPACE: dx=-1; delete=true; moveFirst=true; break; case KeyEvent.VK_DELETE: delete=true; break; } break; case KeyEvent.KEY_TYPED: char ch0=e.getKeyChar(); int kk=e.getKeyCode(); if(cur!=null){ dx=1; if(Character.isLetterOrDigit(ch0)) ch1=Character.toUpperCase(ch0); else if(ch0==tgc[cgrid].wild || Character.isSpaceChar(ch0)) delete=true; else dx=0; } break; } if(moveFirst && (dx!=0 || dy!=0)){ moveCursor(dx, dy); cur=grid[cgrid].getCursor(); consumed=true; } if(delete) ch1=tgc[cgrid].wild; if(ch1!=0 && cur!=null){ if(crossWord){ checkWildChanges(cur, ch1); } grid[cgrid].setCharAt(cur.x, cur.y, ch1); tgc[cgrid].setCharAt(cur.x, cur.y, ch1); setModified(true); consumed=true; } if(!moveFirst && (dx!=0 || dy!=0)){ moveCursor(dx, dy); consumed=true; } } return consumed; } protected void checkWildChanges(Point pt, char ch){ if(!crossWord) return; char oldCh=grid[cgrid].getCharAt(pt.x, pt.y); boolean deleteWild=(oldCh==tgc[cgrid].wild && ch!=oldCh); boolean addWild=(!deleteWild && ch==tgc[cgrid].wild && ch!=oldCh); if(addWild || deleteWild){ Point items=grid[cgrid].getItemFor(pt.x, pt.y); if(items!=null){ boolean intoWhitesH=grid[cgrid].isIntoWhites(pt, true); boolean intoWhitesV=grid[cgrid].isIntoWhites(pt, false); boolean intoBlacksH=grid[cgrid].isIntoBlacks(pt, true); boolean intoBlacksV=grid[cgrid].isIntoBlacks(pt, false); if(deleteWild){ if(intoWhitesH){ abc[1].deleteActiveBoxContentWith(pt.y, items.x); } else if(intoBlacksH){ abc[1].insertActiveBoxContentWith(pt.y, items.x); } if(intoWhitesV){ altAbc[1].deleteActiveBoxContentWith(pt.x, items.y); } else if(intoBlacksV){ altAbc[1].insertActiveBoxContentWith(pt.x, items.y); } } else{ if(intoWhitesH){ abc[1].insertActiveBoxContentWith(pt.y, items.x); } else if(intoBlacksH){ abc[1].deleteActiveBoxContentWith(pt.y, items.x); } if(intoWhitesV){ altAbc[1].insertActiveBoxContentWith(pt.x, items.y); } else if(intoBlacksV){ altAbc[1].deleteActiveBoxContentWith(pt.x, items.y); } } grid[cgrid].setCellLocked(pt.x, pt.y, addWild); } } } public void focusGained(FocusEvent e){ checkCursor(false); } public void focusLost(FocusEvent e){ checkCursor(true); } public void checkCursor(boolean forceLost){ for(int i=0; i<2; i++){ if(grid[i]!=null){ if(cgrid==i && !forceLost && hasFocus()) grid[i].startCursorBlink(); else grid[i].stopCursorBlink(); } } } private void setPanelSelected(int index){ cgrid=index; parent.panelSelected(cgrid); if(!hasFocus()) requestFocus(); else checkCursor(false); } }