001 ///////////////////////////////////////////////// 002 //This file is part of Sears project. 003 //Subtitle Editor And Re-Synch 004 //A tool to easily modify and resynch movies subtitles. 005 ///////////////////////////////////////////////// 006 //This program is free software; 007 //you can redistribute it and/or modify it under the terms 008 //of the GNU General Public License 009 //as published by the Free Software Foundation; 010 //either version 2 of the License, or (at your option) any later version. 011 ///////////////////////////////////////////////// 012 //Sears project is available under sourceforge 013 //at adress: http://sourceforge.net/projects/sears/ 014 //Copyright (C) 2005 Booba Skaya 015 //Mail: booba.skaya@gmail.com 016 ///////////////////////////////////////////////// 017 018 // some suggestions about this class: floriaen@gmail.com 019 020 package sears.gui; 021 022 import java.awt.Color; 023 import java.awt.Composite; 024 import java.awt.Font; 025 import java.awt.Graphics; 026 import java.awt.Graphics2D; 027 import java.awt.Rectangle; 028 import java.awt.Shape; 029 import java.awt.font.FontRenderContext; 030 import java.awt.font.TextLayout; 031 032 import javax.swing.JLabel; 033 import javax.swing.SwingUtilities; 034 import javax.swing.UIManager; 035 036 import sears.tools.Utils; 037 038 /** 039 * <code>JLabel</code> subclasse with highlight possibility. 040 */ 041 public class SubtitleCellComponent extends JLabel { 042 private static final long serialVersionUID = 859239543259106083L; 043 044 /** the default highlight color */ 045 public static final Color DEFAULT_HIGHLIGTH_COLOR = Color.LIGHT_GRAY; 046 //UIManager.getColor("Table.selectionBackground"); 047 /** default font */ 048 public static final Font DEFAULT_FONT = UIManager.getFont("Table.font"); 049 050 private static final String EMPTY_STRING = ""; 051 // the substring to highlight 052 private static String highligthString; 053 private boolean highlighting; 054 055 private int rowHeight; 056 057 private FontRenderContext frc; 058 059 /** 060 * Instantiates a new object 061 * @param rowHeight the height of row defines by the table 062 */ 063 public SubtitleCellComponent(int rowHeight) { 064 super(); 065 setFont(DEFAULT_FONT); 066 frc = new FontRenderContext(null, true, false); 067 setHighlightedString(EMPTY_STRING); 068 this.rowHeight = rowHeight; 069 } 070 071 /** 072 * Sets the highlighted string 073 * @param str the string to highlight 074 */ 075 public void setHighlightedString(String str) { 076 if( str == null || str.trim().length() == 0 ) { 077 str = EMPTY_STRING; 078 highlighting = false; 079 } else { 080 highlighting = true; 081 } 082 highligthString = str.toUpperCase(); 083 084 } 085 086 /** 087 * Returns the sub string 088 * @return the sub string or null 089 */ 090 public static String getSubString() { 091 return highligthString; 092 } 093 094 /** 095 * Returns the bounds of substring glyph, begin at <code>index</code> 096 * @param index the index of the first char of the searched word 097 * @param str the word to search, the highlighted word 098 * @return a <tt>Rectangle</tt> object, the substring bounds 099 */ 100 public Rectangle getBoundsBeginAtIndex(int index, String str) { 101 // ensure coherence, throw exception 102 Rectangle bounds = null; 103 String text = formatText(this.getText()); 104 TextLayout textLayout = new TextLayout(text, getFont(), frc); 105 // IllegalArgumentException is thrown by #ensure(String) method before 106 // it's made by the TextLayout#getBlackBoxBounds(...) method 107 text = text.toUpperCase(); 108 109 // X position: 110 Shape blackBoxBounds = textLayout.getBlackBoxBounds(index, index + str.length()); 111 // Y DISTANCE: 112 double tyDistance = rowHeight/2 + (textLayout.getAscent() - textLayout.getDescent())/2; 113 // BOUNDS: 114 bounds = new Rectangle( 115 blackBoxBounds.getBounds().width, 116 (int) textLayout.getAscent() 117 ); 118 bounds.translate((int) blackBoxBounds.getBounds2D().getX(), (int) tyDistance); 119 return bounds; 120 } 121 122 /** 123 * Returns the searched sub string (respect lower and upper case states) in the specified location in subtitle text 124 * @param index the first index of the first char of the searched text 125 * @param str the searched text 126 * @return the searched text in the subtitle text 127 */ 128 public String getSubStringBeginAtIndex(int index, String str) { 129 String text = formatText(getText()); 130 // StringIndexOutOfBoundsException is thrown (as IllegalArgumentException) 131 // by #ensure(String) method before it's thrown by the String#substring(...) method 132 return text.substring(index, index + str.length()); 133 } 134 135 /* 136 * (non-Javadoc) 137 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) 138 */ 139 public void paintComponent(Graphics g) { 140 super.paintComponent(g); 141 Graphics2D gr = (Graphics2D) g; 142 Color defaultColor = gr.getColor(); 143 // PAINT BACKGROUND: 144 gr.setColor(getBackground()); 145 gr.fillRect(0, 0, getWidth(), getHeight()); 146 String text = formatText(getText()); 147 TextLayout layout = new TextLayout(text, gr.getFont(), gr.getFontRenderContext()); 148 if( highlighting ) { 149 // calls the highlight method: 150 paintHighlightShape(gr, layout, text); 151 } 152 153 // PAINT TEXT: 154 gr.setColor(getForeground()); 155 156 // center layout: 157 float layoutYCentered = getHeight()/2 + (layout.getAscent() - layout.getDescent())/2; 158 this.setSize(getWidth(), getHeight()); 159 layout.draw(gr, 0, layoutYCentered); 160 gr.setColor(defaultColor); 161 } 162 163 /** 164 * Graphics context could be modified by this method. 165 * @param gr the graphic context 166 * @param layout the layout which contain text to highlight 167 * @param text the text to highlight 168 */ 169 private void paintHighlightShape(Graphics2D gr, TextLayout layout, String text) { 170 Composite defaultComposite = gr.getComposite(); 171 // real size of the cell 172 Rectangle cell = SwingUtilities.getLocalBounds(this); 173 if(cell != null) { 174 text = text.toUpperCase(); 175 int start = -1; 176 while( (start = text.indexOf(highligthString, start+1)) != -1 ) { 177 Shape sh = layout.getLogicalHighlightShape(start, start+highligthString.length(), cell); 178 gr.setColor(DEFAULT_HIGHLIGTH_COLOR); 179 gr.fill(sh); 180 } 181 } 182 gr.setComposite(defaultComposite); 183 } 184 185 /** 186 * Format the text given in parameters 187 * @param text the text to format 188 * @return the formatted text 189 */ 190 private String formatText(String text) { 191 if( text.equals("")) { 192 text = " "; 193 } else { 194 text = text.replace(Utils.LINE_SEPARATOR, " "); 195 } 196 return text; 197 } 198 }