From 3c82f0a24c15783727c5cf1a86cb3d79633662e7 Mon Sep 17 00:00:00 2001 From: dchandler Date: Sat, 28 Sep 2002 00:53:39 +0000 Subject: [PATCH] Initial revision --- source/MessageBundle.properties | 75 + source/MessageBundle_de_DE.properties | 75 + source/MessageBundle_zh_CN.properties | 34 + source/chinesebundle.txt | 34 + source/org/thdl/quilldriver/QD.java | 1651 +++++++++++++++++ source/org/thdl/quilldriver/QDPlayer.java | 405 ++++ source/org/thdl/quilldriver/QDShell.java | 159 ++ source/org/thdl/quilldriver/clock.gif | Bin 0 -> 774 bytes source/org/thdl/quilldriver/face01a.jpg | Bin 0 -> 992 bytes source/org/thdl/quilldriver/face02a.jpg | Bin 0 -> 3653 bytes source/org/thdl/quilldriver/face03a.jpg | Bin 0 -> 854 bytes source/org/thdl/quilldriver/face04a.jpg | Bin 0 -> 1403 bytes source/org/thdl/quilldriver/face05a.jpg | Bin 0 -> 921 bytes source/org/thdl/quilldriver/face06a.jpg | Bin 0 -> 4358 bytes source/org/thdl/quilldriver/face07a.jpg | Bin 0 -> 3835 bytes source/org/thdl/quilldriver/face08a.jpg | Bin 0 -> 1647 bytes source/org/thdl/quilldriver/face09a.jpg | Bin 0 -> 2872 bytes source/org/thdl/quilldriver/face10a.jpg | Bin 0 -> 948 bytes source/org/thdl/quilldriver/face11a.jpg | Bin 0 -> 5043 bytes source/org/thdl/quilldriver/face12a.jpg | Bin 0 -> 3748 bytes source/org/thdl/quilldriver/face13a.jpg | Bin 0 -> 1249 bytes source/org/thdl/savant/AnnotationPlayer.java | 7 + source/org/thdl/savant/Savant.java | 313 ++++ source/org/thdl/savant/SavantFileView.java | 36 + source/org/thdl/savant/SavantShell.java | 330 ++++ source/org/thdl/savant/SoundPanel.java | 458 +++++ .../org/thdl/savant/TextHighlightPlayer.java | 104 ++ source/org/thdl/savant/TextPlayer.java | 93 + source/org/thdl/savant/TranscriptView.java | 13 + source/org/thdl/savant/TwoWayTextPlayer.java | 106 ++ source/org/thdl/savant/tib/English.java | 196 ++ source/org/thdl/savant/tib/Tibetan.java | 205 ++ .../org/thdl/savant/tib/TibetanEnglish.java | 213 +++ source/org/thdl/savant/tib/TibetanWylie.java | 216 +++ .../thdl/savant/tib/TibetanWylieEnglish.java | 218 +++ source/org/thdl/savant/tib/Wylie.java | 196 ++ source/org/thdl/savant/tib/WylieEnglish.java | 209 +++ source/org/thdl/savant/ucuchi/All.java | 225 +++ source/org/thdl/savant/ucuchi/English.java | 196 ++ source/org/thdl/savant/ucuchi/Quechua.java | 195 ++ .../thdl/savant/ucuchi/QuechuaEnglish.java | 217 +++ .../thdl/savant/ucuchi/SegmentedQuechua.java | 217 +++ .../org/thdl/tib/text/DuffCellRenderer.java | 140 ++ 43 files changed, 6536 insertions(+) create mode 100644 source/MessageBundle.properties create mode 100644 source/MessageBundle_de_DE.properties create mode 100644 source/MessageBundle_zh_CN.properties create mode 100644 source/chinesebundle.txt create mode 100644 source/org/thdl/quilldriver/QD.java create mode 100644 source/org/thdl/quilldriver/QDPlayer.java create mode 100644 source/org/thdl/quilldriver/QDShell.java create mode 100644 source/org/thdl/quilldriver/clock.gif create mode 100644 source/org/thdl/quilldriver/face01a.jpg create mode 100644 source/org/thdl/quilldriver/face02a.jpg create mode 100644 source/org/thdl/quilldriver/face03a.jpg create mode 100644 source/org/thdl/quilldriver/face04a.jpg create mode 100644 source/org/thdl/quilldriver/face05a.jpg create mode 100644 source/org/thdl/quilldriver/face06a.jpg create mode 100644 source/org/thdl/quilldriver/face07a.jpg create mode 100644 source/org/thdl/quilldriver/face08a.jpg create mode 100644 source/org/thdl/quilldriver/face09a.jpg create mode 100644 source/org/thdl/quilldriver/face10a.jpg create mode 100644 source/org/thdl/quilldriver/face11a.jpg create mode 100644 source/org/thdl/quilldriver/face12a.jpg create mode 100644 source/org/thdl/quilldriver/face13a.jpg create mode 100644 source/org/thdl/savant/AnnotationPlayer.java create mode 100644 source/org/thdl/savant/Savant.java create mode 100644 source/org/thdl/savant/SavantFileView.java create mode 100644 source/org/thdl/savant/SavantShell.java create mode 100644 source/org/thdl/savant/SoundPanel.java create mode 100644 source/org/thdl/savant/TextHighlightPlayer.java create mode 100644 source/org/thdl/savant/TextPlayer.java create mode 100644 source/org/thdl/savant/TranscriptView.java create mode 100644 source/org/thdl/savant/TwoWayTextPlayer.java create mode 100644 source/org/thdl/savant/tib/English.java create mode 100644 source/org/thdl/savant/tib/Tibetan.java create mode 100644 source/org/thdl/savant/tib/TibetanEnglish.java create mode 100644 source/org/thdl/savant/tib/TibetanWylie.java create mode 100644 source/org/thdl/savant/tib/TibetanWylieEnglish.java create mode 100644 source/org/thdl/savant/tib/Wylie.java create mode 100644 source/org/thdl/savant/tib/WylieEnglish.java create mode 100644 source/org/thdl/savant/ucuchi/All.java create mode 100644 source/org/thdl/savant/ucuchi/English.java create mode 100644 source/org/thdl/savant/ucuchi/Quechua.java create mode 100644 source/org/thdl/savant/ucuchi/QuechuaEnglish.java create mode 100644 source/org/thdl/savant/ucuchi/SegmentedQuechua.java create mode 100644 source/org/thdl/tib/text/DuffCellRenderer.java diff --git a/source/MessageBundle.properties b/source/MessageBundle.properties new file mode 100644 index 0000000..d98b861 --- /dev/null +++ b/source/MessageBundle.properties @@ -0,0 +1,75 @@ +Project = Project +ProjectDetails = Project Details +Speakers = Speakers +TimeCoding = Time Coding +AdjustTimeCode = Adjust Time Code +In = Start +Out = Stop +PlaySegment = Play Segment +NewProject = New Project +TitleColon = Title: +TypeNewTitleColon = Type new title: +NoMedia = No media +MediaColon = Media: +NoTranscript = No transcript +TranscriptColon = Transcript: +KeyboardInputMethod = Keyboard Input Method +TranscriberName = Transcriber Name +TranscriberTask = Transcriber Task +Add = Add +FaceColon = Face: +NameColon = Name: +EnterNewSpeakerInfo = Enter new speaker info +Edit = Edit +EditSpeakerInfo = Edit speaker info +Remove = Remove +SureDeleteSpeaker = Are you sure you want to delete this speaker? +Warning = Warning! +Face = Face +Name = Name +SaveCurrent = Save the current transcript +OpenExisting = Open an existing transcript +WhatToDo = What do you want to do? +ChooseOne = Choose an option +Play = Play +Pause = Pause +Mode = Mode +Edit = Edit +ReadOnly = Read-only +View = View +Previous = Previous +Current = Current +Next = Next +SuppressTimes = Hide times +Search = Search +FindText = Find text +ReplaceText = Replace text +FindSpeaker = Find speaker +FindTime = Find time +Cut = Cut +Copy = Copy +Paste = Paste +SelectAll = Select all +InsertSpeaker = Insert speaker +InsertOneTime = Insert a time +InsertTwoTimes = Insert two times +New = New +Open = Open +Close = Close +Save = Save +SaveAs = Save as +Quit = Quit +Keyboard = Keyboard +Preferences = Preferences +FindHeading = Search +FindReplaceHeading = Search and Replace +FindWhat = Find what +ReplaceWith = Replace with +ReplaceQ = Replace? +FindNextYesNo = Find next? +StartFromBeginning = You've reached the end of the document. Do you want to continue searching from the beginning? +TextFound = Text found. +Replace = Replace +ReplaceAll = Replace all +NoReplace = Don't replace +Cancel = Cancel \ No newline at end of file diff --git a/source/MessageBundle_de_DE.properties b/source/MessageBundle_de_DE.properties new file mode 100644 index 0000000..125956b --- /dev/null +++ b/source/MessageBundle_de_DE.properties @@ -0,0 +1,75 @@ +Project = Project Details +ProjectDetails = Projekt +Speakers = Sprecher +TimeCoding = Zeitcode +AdjustTimeCode = Zeitcode regulieren +In = Start +Out = Stop +PlaySegment = Abschnitt abspielen +NewProject = Neues Projekt +TitleColon = Titel: +TypeNewTitleColon = Neue Titeleingabe +NoMedia = Keine Audio/Video-Medien +MediaColon = Audio/Video-Medien: +NoTranscript = Keine Transkription +TranscriptColon = Text-Transkription: +KeyboardInputMethod = Tastatur Eingabemethode +TranscriberName = Transkribierer-Name: +TranscriberTask = Transkribierer-Aufgabe: +Add = Hinzuf黦en +FaceColon = Gesicht +NameColon = Name: +EnterNewSpeakerInfo = Eingabe neue Sprecher-Information +Edit = Bearbeiten +EditSpeakerInfo = Bearbeiten der Srecher-Information +Remove = Entfernen +SureDeleteSpeaker = Wollen Sie wirklich diesen Sprecher l鰏chen? +Warning = Warnung! +Face = Gesicht +Name = Name +SaveCurrent = Gegenw鋜tige Transkription speichern +OpenExisting = Bereits bearbeitete Transkription 鰂fnen +WhatToDo = Was m鯿hten Sie tun? +ChooseOne = W鋒len Sie eine M鰃lichkeit +Play = Abspielen +Pause = Pause +Mode = Moduswahl +Edit = Bearbeiten der Transkription +ReadOnly = Sichten der Transkription +View = Sichten +Previous = Vorhergehender Satz +Current = Gegenw鋜tiger Satz +Next = N鋍hster Satz +SuppressTimes = Entfernen der Zeitzeichen +Search = Search +FindText = Text finden +ReplaceText = Text ersetzen +FindSpeaker = Sprecher finden +FindTime = Zeitabschnitt finden +Cut = Schneiden +Copy = Kopieren +Paste = Einf黦en +SelectAll = Alles ausw鋒len +InsertSpeaker = Sprecher einf黦en +InsertOneTime = Einmal einf黦en +InsertTwoTimes = Zweimal einf黦en +New = Neu +Open = 謋fnen +Close = Schlie遝n +Save = Speichern +SaveAs = Speichern als +Quit = Quit +Keyboard = Tastatur Eingabemethode +Preferences = Pr鋐erenzen +FindHeading = Search +FindReplaceHeading = Search and Replace +FindWhat = Find what +ReplaceWith = Replace with +ReplaceQ = Replace? +FindNextYesNo = Find next? +StartFromBeginning = You've reached the end of the document. Do you want to continue searching from the beginning? +TextFound = Text found. +Replace = Replace +ReplaceAll = Replace all +NoReplace = Don't replace +Cancel = Cancel \ No newline at end of file diff --git a/source/MessageBundle_zh_CN.properties b/source/MessageBundle_zh_CN.properties new file mode 100644 index 0000000..6e7084c --- /dev/null +++ b/source/MessageBundle_zh_CN.properties @@ -0,0 +1,34 @@ +Project = \u9879\u76ee +Speakers = \u5bf9\u8bdd\u8005 +TimeCoding = \u65f6\u95f4\u4ee3\u7801 +AdjustTimeCode = \u8c03\u6574\u65f6\u95f4 +In =\u5f00\u59cb +Out = \u7ed3\u675f +PlaySegment = \u663e\u793a\u7a97\u53e3 +NewProject =\u65e0\u65b0\u9879\u76ee\u6587\u4ef6 +TitleColon = \u9898\u76ee +TypeNewTitleColon = \u65b0\u9898\u76ee +NoMedia = \u65e0\u5a92\u4f53\u6587\u4ef6 +MediaColon = \u5a92\u4f53 +NoTranscript = \u65e0\u6587\u672c\u6587\u4ef6 +TranscriptColon = \u6587\u5b57 +KeyboardInputMethod = \u952e\u76d8\u5e03\u5c40 +TranscriberName = \u8bb0\u5f55\u8005 +TranscriberTask = \u8bb0\u5f55\u5185\u5bb9 +Add = \u589e\u52a0 +FaceColon = \u9009\u62e9\u8138\u5f62 +NameColon = \u53d6\u540d +EnterNewSpeakerInfo = \u589e\u52a0\u65b0\u7528\u6237\u7a97\u53e3 +Edit = \u7f16\u8f91 +EditSpeakerInfo = \u7f16\u8f91\u7a97\u53e3 +Remove = \u5220\u9664 +SureDeleteSpeaker = \u786e\u5b9e\u5220\u9664\u5417\uff1f +Warning = \u8b66\u544a\uff01 +Face = \u8138 +Name = \u540d +SaveCurrent = \u4fdd\u5b58 +OpenExisting =\u6253\u5f00 +WhatToDo =\u9009\u62e9 +ChooseOne =\u9009\u62e9\u4e4b\u4e00 +Play = \u64ad\u653e +Pause = \u6682\u505c diff --git a/source/chinesebundle.txt b/source/chinesebundle.txt new file mode 100644 index 0000000..b4c2d82 --- /dev/null +++ b/source/chinesebundle.txt @@ -0,0 +1,34 @@ +Project = 项目 +Speakers = 对话者 +TimeCoding = 时间代码 +AdjustTimeCode = 调整时间 +In =开始 +Out = 结束 +PlaySegment = 显示窗口 +NewProject =无新项目文件 +TitleColon = 题目 +TypeNewTitleColon = 新题目 +NoMedia = 无媒体文件 +MediaColon = 媒体 +NoTranscript = 无文本文件 +TranscriptColon = 文字 +KeyboardInputMethod = 键盘布局 +TranscriberName = 记录者 +TranscriberTask = 记录内容 +Add = 增加 +FaceColon = 选择脸形 +NameColon = 取名 +EnterNewSpeakerInfo = 增加新用户窗口 +Edit = 编辑 +EditSpeakerInfo = 编辑窗口 +Remove = 删除 +SureDeleteSpeaker = 确实删除吗? +Warning = 警告! +Face = 脸 +Name = 名 +SaveCurrent = 保存 +OpenExisting =打开 +WhatToDo =选择 +ChooseOne =选择之一 +Play = 播放 +Pause = 暂停 \ No newline at end of file diff --git a/source/org/thdl/quilldriver/QD.java b/source/org/thdl/quilldriver/QD.java new file mode 100644 index 0000000..508b964 --- /dev/null +++ b/source/org/thdl/quilldriver/QD.java @@ -0,0 +1,1651 @@ +package org.thdl.quilldriver; + +import java.util.*; +import java.io.*; +import java.net.*; +import javax.swing.*; +import javax.swing.table.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.plaf.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.dnd.*; +import java.awt.datatransfer.*; +import org.thdl.tib.input.*; +import org.thdl.tib.text.*; +import org.thdl.tib.text.TibetanDocument.*; + +import org.jdom.*; +import org.jdom.input.SAXBuilder; +import org.jdom.output.XMLOutputter; +import org.jdom.transform.JDOMSource; +import javax.xml.transform.stream.*; +import javax.xml.transform.*; + + +public class QD extends JDesktopPane { + //project related data + protected Project project; + + //speaker related + protected SpeakerTable speakerTable; + + //video related + protected QDPlayer player = null; + + //frame related + protected JInternalFrame videoFrame = null; + protected JInternalFrame textFrame = null; + protected JInternalFrame actionFrame = null; + + //miscellaneous stuff + protected JFileChooser fileChooser = null; + public JTabbedPane jtp; + public TimeCodeManager tcp = null; + public SpeakerManager spm = null; + public JTextPane pane; + public Hashtable actions; + public ImageIcon clockIcon; + public static final String componentStyleName = "Component"; + public Style componentStyle; + public DataFlavor timeFlavor; + + protected JMenu editMenu; + + protected ResourceBundle messages; + + protected java.util.List work; + protected Work currentWork; + + protected DuffPane sharedDP = new DuffPane(); + protected DuffPane sharedDP2 = new DuffPane(); + + protected TibetanDocument findDoc = null; + protected TibetanDocument replaceDoc = null; + +protected URL keyboard_url = null; + + +public QD(ResourceBundle messages) { + this.messages = messages; + + setBackground(new JFrame().getBackground()); + setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + + clockIcon = new ImageIcon(QD.class.getResource("clock.gif")); + timeFlavor = new DataFlavor(Integer.class, "time"); + + fileChooser = new JFileChooser(); + fileChooser.addChoosableFileFilter(new XMLFilter()); + + Action insert1TimeAction = new AbstractAction("insert1Time", null) { + public void actionPerformed(ActionEvent e) { + new TimePoint(pane, clockIcon, tcp.getOutTime()); + tcp.setInTime(tcp.getOutTime().intValue()); + tcp.setOutTime(player.getLastTime()); + } + }; + + Action insert2TimesAction = new AbstractAction("insert2Times", null) { + public void actionPerformed(ActionEvent e) { + int p1 = pane.getSelectionStart(); + int p2 = pane.getSelectionEnd(); + pane.setCaretPosition(p1); + new TimePoint(pane, clockIcon, tcp.getInTime()); + pane.setCaretPosition(p2+1); + new TimePoint(pane, clockIcon, tcp.getOutTime()); + if (p1 == p2) + pane.setCaretPosition(pane.getCaretPosition()-1); + tcp.setInTime(tcp.getOutTime().intValue()); + tcp.setOutTime(player.getLastTime()); + } + }; + + Action saveAction = new AbstractAction("saveTranscript", null) { + public void actionPerformed(ActionEvent e) { + getSave(); + } + }; + + JTextPane tp = new JTextPane(); + Keymap keymap = tp.addKeymap("QDBindings", tp.getKeymap()); + + KeyStroke insert1TimeKey = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, Event.CTRL_MASK); + KeyStroke insert2TimesKey = KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, Event.CTRL_MASK); + KeyStroke saveKey = KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK); + + keymap.addActionForKeyStroke(insert1TimeKey, insert1TimeAction); + keymap.addActionForKeyStroke(insert2TimesKey, insert2TimesAction); + keymap.addActionForKeyStroke(saveKey, saveAction); + + Speaker[] speakers = new Speaker[0]; + SpeakerData speakerData = new SpeakerData(speakers, keymap); + speakerTable = new SpeakerTable(speakerData); + + pane = new DuffPane(); + pane.setKeymap(keymap); + new TimePointDropTarget(pane); + + work = new ArrayList(); + currentWork = new Work(); + work.add(currentWork); + + JPanel textPanel = new JPanel(new BorderLayout()); + textPanel.add("Center", new JScrollPane(pane)); + + JPanel actionPanel = new JPanel(new BorderLayout()); + jtp = new JTabbedPane(); + project = null; + spm = new SpeakerManager(speakerTable); + jtp.addTab(messages.getString("Speakers"), spm); + actionPanel.add("Center", jtp); + + //(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) + videoFrame = new JInternalFrame(null, false, false, false, false); + videoFrame.setVisible(true); + videoFrame.setLocation(0,0); + videoFrame.setSize(0,0); + add(videoFrame, JLayeredPane.POPUP_LAYER); + invalidate(); + validate(); + repaint(); + + textFrame = new JInternalFrame(null, false, false, false, true); + textFrame.setVisible(true); + textFrame.setContentPane(textPanel); + textFrame.setLocation(0,0); + textFrame.setSize(0,0); + textFrame.setJMenuBar(getTextMenuBar()); + add(textFrame, JLayeredPane.DEFAULT_LAYER); + invalidate(); + validate(); + repaint(); + + actionFrame = new JInternalFrame(null, false, false, false, true); + actionFrame.setVisible(true); + actionFrame.setContentPane(actionPanel); + actionFrame.setLocation(0,0); + actionFrame.setSize(0,0); + add(actionFrame, JLayeredPane.DEFAULT_LAYER); + invalidate(); + validate(); + repaint(); + + addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent ce) { + Dimension d = videoFrame.getSize(); + if (d.width == 0 && d.height == 0) + videoFrame.setSize(getSize().width / 2, 0); + textFrame.setLocation(videoFrame.getSize().width, 0); + textFrame.setSize(getSize().width - videoFrame.getSize().width, getSize().height); + actionFrame.setLocation(0, videoFrame.getSize().height); + actionFrame.setSize(videoFrame.getSize().width, getSize().height - videoFrame.getSize().height); + } + }); +} + +private void startTimer() { + final java.util.Timer timer = new java.util.Timer(true); + timer.schedule(new TimerTask() { + public void run() + { + if (player.cmd_isSized()) + { + timer.cancel(); + + if (tcp != null) + jtp.remove(tcp); + tcp = new TimeCodeManager(); + jtp.addTab(messages.getString("TimeCoding"), tcp); + + videoFrame.setContentPane(player); + videoFrame.pack(); + videoFrame.setMaximumSize(videoFrame.getSize()); + invalidate(); + validate(); + repaint(); + textFrame.setLocation(videoFrame.getSize().width, 0); + textFrame.setSize(getSize().width - videoFrame.getSize().width, getSize().height); + invalidate(); + validate(); + repaint(); + actionFrame.setLocation(0, videoFrame.getSize().height); + actionFrame.setSize(videoFrame.getSize().width, getSize().height - videoFrame.getSize().height); + invalidate(); + validate(); + repaint(); + } + }}, 0, 50); +} + +private void createActionTable(JTextComponent textComponent) { + actions = new Hashtable(); + Action[] actionsArray = textComponent.getActions(); + for (int i = 0; i < actionsArray.length; i++) { + Action a = actionsArray[i]; + actions.put(a.getValue(Action.NAME), a); + } +} + +private Action getActionByName(String name) { + return (Action)(actions.get(name)); +} + +class TimePoint extends JLabel implements DragGestureListener, DragSourceListener { + StyledDocument doc; + Position pos; + Integer time; + + TimePoint(final JTextPane tp, Icon icon, Integer time) { + super(icon); + this.time = time; + setCursor(new Cursor(Cursor.HAND_CURSOR)); + setToolTipText(getTimeAsString()); + DragSource dragSource = DragSource.getDefaultDragSource(); + dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) + playSegment(); + else { + SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getLastTime(), 10); + JSpinner spinner = new JSpinner(snm1); + spinner.setPreferredSize(new Dimension(100, 40)); + spinner.setValue(getTime()); + if (JOptionPane.showOptionDialog(tp, spinner, messages.getString("AdjustTimeCode"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null) == JOptionPane.OK_OPTION) + setTime((Integer)spinner.getValue()); + } + } + }); + doc = tp.getStyledDocument(); + tp.insertComponent(this); + try { //insertions occur prior to position, so position should be right before icon after icon is inserted + pos = doc.createPosition(tp.getCaretPosition()-1); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + public void setTime(Integer t) { + time = t; + setToolTipText(getTimeAsString()); + } + public Integer getTime() { + return time; + } + public String getTimeAsString() { + return String.valueOf(time); + } + public void playSegment() { + int i=pos.getOffset(); + System.out.println(String.valueOf(i)); + for (i++; i in.intValue()) + player.cmd_play(in, out); + } + }); + JPanel ps = new JPanel(); + ps.add(playSegButton); + +/* + JButton playButton = new JButton(messages.getString("Play")); + JButton pauseButton = new JButton(messages.getString("Pause")); + + playButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (player != null) + player.cmd_play(); + } + }); + pauseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (player != null) + player.cmd_stop(); + } + }); +*/ + + Box box = Box.createVerticalBox(); + box.add(inPanel); + box.add(outPanel); + box.add(ps); + + add("North", box); + } + public Integer getInTime() { + return (Integer)inSpinner.getValue(); + } + public Integer getOutTime() { + return (Integer)outSpinner.getValue(); + } + public void setInTime(int k) { + inSpinner.setValue(new Integer(k)); + } + public void setOutTime(int k) { + outSpinner.setValue(new Integer(k)); + } +} + +class Work { + public String name; + public String task; + public String startDate; + public String duration; + public Date beginTime; + + Work() { + beginTime = new Date(); + startDate = beginTime.toString(); + } + public void stopWork() { + Date stopTime = new Date(); + long milliseconds = stopTime.getTime() - beginTime.getTime(); + int minutes = new Long(milliseconds / 1000 / 60).intValue(); + duration = String.valueOf(minutes); + name = project.getTranscriberName(); + task = project.getTranscriberTask(); + } +} + +class Project extends JPanel { + JTextField titleField, mediaField, transcriptField, nameField, taskField; + File transcript = null; + File media = null; + +public String getTitle() { + return titleField.getText(); +} +public void setTitle(String s) { + titleField.setText(s); +} +public String getTranscriberName() { + return nameField.getText(); +} +public void setTranscriberName(String s) { + nameField.setText(s); +} +public String getTranscriberTask() { + return taskField.getText(); +} +public void setTranscriberTask(String s) { + taskField.setText(s); +} +public File getTranscript() { + return transcript; +} +public void setTranscript(File f) { //doesn't actually load or save transcript, just changes changeTranscript label + transcript = f; + if (transcript == null) + transcriptField.setText(""); + else + transcriptField.setText(transcript.getPath()); +} +public File getMedia() { + return media; +} +public void setMedia(File f) { + if (f == null) { + media = f; + mediaField.setText(media.getPath()); + if (player != null) { + player.cmd_stop(); + player.destroy(); + videoFrame.getContentPane().remove(player); + videoFrame.getContentPane().invalidate(); + videoFrame.getContentPane().validate(); + videoFrame.getContentPane().repaint(); + player = null; + videoFrame.setSize(new Dimension(QD.this.getSize().width / 2, 0)); + jtp.remove(tcp); + tcp = null; + actionFrame.setLocation(0,0); + actionFrame.setSize(new Dimension(actionFrame.getSize().width, QD.this.getSize().height)); + } + } + else { + try { + URL url = f.toURL(); + + if (player != null) { + player.cmd_stop(); + player.destroy(); + } + player = new QDPlayer(QD.this, url); + media = f; + mediaField.setText(media.getPath()); + startTimer(); + } catch (MalformedURLException murle) { + murle.printStackTrace(); + } + } +} + +public Project() { + JPanel p = new JPanel(new GridLayout(2,2)); + titleField = new JTextField(); + int preferredHeight = titleField.getPreferredSize().height; + titleField.setPreferredSize(new Dimension(300, preferredHeight)); + mediaField = new JTextField(); + mediaField.setPreferredSize(new Dimension(300, preferredHeight)); + mediaField.setEditable(false); + transcriptField = new JTextField(); + transcriptField.setPreferredSize(new Dimension(300, preferredHeight)); + transcriptField.setEditable(false); + nameField = new JTextField(); + nameField.setPreferredSize(new Dimension(300, preferredHeight)); + taskField = new JTextField(); + taskField.setPreferredSize(new Dimension(300, preferredHeight)); + + Box box = Box.createVerticalBox(); + JPanel p1 = new JPanel(); + p1.add(new JLabel(messages.getString("TitleColon"))); + p1.add(titleField); + JPanel p1b = new JPanel(new BorderLayout()); + p1b.add("East", p1); + p1b.setAlignmentX(Component.RIGHT_ALIGNMENT); + + JPanel p2 = new JPanel(); + p2.add(new JLabel(messages.getString("MediaColon"))); + p2.add(mediaField); + JPanel p2b = new JPanel(new BorderLayout()); + p2b.add("East", p2); + p2b.setAlignmentX(Component.RIGHT_ALIGNMENT); + + JPanel p3 = new JPanel(); + p3.add(new JLabel(messages.getString("TranscriptColon"))); + p3.add(transcriptField); + JPanel p3b = new JPanel(new BorderLayout()); + p3b.add("East", p3); + p3b.setAlignmentX(Component.RIGHT_ALIGNMENT); + + JPanel p4 = new JPanel(); + p4.add(new JLabel(messages.getString("TranscriberName"))); + p4.add(nameField); + JPanel p4b = new JPanel(new BorderLayout()); + p4b.add("East", p4); + p4b.setAlignmentX(Component.RIGHT_ALIGNMENT); + + JPanel p5 = new JPanel(); + p5.add(new JLabel(messages.getString("TranscriberTask"))); + p5.add(taskField); + JPanel p5b = new JPanel(new BorderLayout()); + p5b.add("East", p5); + p5b.setAlignmentX(Component.RIGHT_ALIGNMENT); + + box.add(p1b); + box.add(p2b); + box.add(p3b); + box.add(p4b); + box.add(p5b); + + JPanel pBig = new JPanel(new BorderLayout()); + pBig.add("West", box); + + setLayout(new BorderLayout()); + add("North", pBig); +} +} + +public void changeKeyboard(ActionEvent e) { + DuffPane dp = (DuffPane)pane; + if (e.getActionCommand().equals("wylie")) { + dp.registerKeyboard(); + // project.tName.setupKeyboard(); + // project.tTask.setupKeyboard(); + sharedDP.setupKeyboard(); + sharedDP2.setupKeyboard(); + return; + } + keyboard_url = null; + if (e.getActionCommand().equals("sambhota1")) + keyboard_url = TibetanMachineWeb.class.getResource("sambhota_keyboard_1.ini"); + else if (e.getActionCommand().equals("tcc1")) + keyboard_url = TibetanMachineWeb.class.getResource("tcc_keyboard_1.ini"); + else if (e.getActionCommand().equals("tcc2")) + keyboard_url = TibetanMachineWeb.class.getResource("tcc_keyboard_2.ini"); + dp.registerKeyboard(keyboard_url); +// project.tName.setupKeyboard(); +// project.tTask.setupKeyboard(); + sharedDP.setupKeyboard(); + sharedDP2.setupKeyboard(); +} + +public boolean getSave() { + if (pane.getDocument().getLength() == 0 && speakerTable.getRowCount() == 0) + return true; //nothing to save + + if (project.getTranscript() == null) { + if (project.getMedia() == null) + fileChooser.setSelectedFile(null); + else { + String path = project.getMedia().getPath(); + path = path.substring(0, path.lastIndexOf('.')) + ".xml"; + fileChooser.setSelectedFile(new File(path)); + } + if (fileChooser.showSaveDialog(QD.this) == JFileChooser.APPROVE_OPTION) { + File f = fileChooser.getSelectedFile(); + project.setTranscript(f); + } else + return false; + } + currentWork.stopWork(); + +//change keyboard back to wylie for a second + DuffPane dp = (DuffPane)pane; +if (keyboard_url != null) { + + dp.registerKeyboard(); + // project.tName.setupKeyboard(); + // project.tTask.setupKeyboard(); + sharedDP.setupKeyboard(); + sharedDP.setupKeyboard(); +} + + + org.jdom.Element title = new org.jdom.Element("title"); + title.setText(project.getTitle().trim()); + + org.jdom.Element media = new org.jdom.Element("mediafile"); + if (project.getMedia() == null) + media.setText(""); + else { + String tPath = project.getTranscript().getPath(); + String mPath = project.getMedia().getPath(); + if (tPath.substring(0, tPath.lastIndexOf(File.separatorChar)).equals(mPath.substring(0, mPath.lastIndexOf(File.separatorChar)))) + media.setText(mPath.substring(mPath.lastIndexOf(File.separatorChar)+1)); + else + media.setText(mPath); + } + + org.jdom.Element speakers = new org.jdom.Element("speakers"); + SpeakerData sd = (SpeakerData)speakerTable.getModel(); + java.util.List allSpeakers = sd.getSpeakers(); + Iterator spIter = allSpeakers.iterator(); + while (spIter.hasNext()) { + Speaker sp = (Speaker)spIter.next(); + org.jdom.Element speaker = new org.jdom.Element("speaker"); + speaker.setAttribute("iconid", String.valueOf(sp.getIconID())); + speaker.setText(sp.getName()); + speakers.addContent(speaker); + } + + org.jdom.Element works = new org.jdom.Element("workhistory"); + Iterator wkIter = work.iterator(); + while (wkIter.hasNext()) { + Work wkUnit = (Work)wkIter.next(); + org.jdom.Element wk = new org.jdom.Element("work"); + org.jdom.Element name = new org.jdom.Element("name"); + name.setText(wkUnit.name); + org.jdom.Element task = new org.jdom.Element("task"); + task.setText(wkUnit.task); + org.jdom.Element date = new org.jdom.Element("start"); + date.setText(wkUnit.startDate); + org.jdom.Element duration = new org.jdom.Element("duration"); + duration.setText(wkUnit.duration); + wk.addContent(name); + wk.addContent(task); + wk.addContent(date); + wk.addContent(duration); + works.addContent(wk); + } + + org.jdom.Element meta = new org.jdom.Element("metadata"); + meta.addContent(title); + meta.addContent(media); + meta.addContent(speakers); + meta.addContent(works); + + org.jdom.Element text = new org.jdom.Element("text"); + TibetanDocument doc = (TibetanDocument)pane.getDocument(); + ImageIcon[] icons = sd.getSpeakerIcons(); + int lastPoint = 0; + int k; + for (k=0; k 0) + dp.setText(""); + java.util.List textContent = text.getContent(); + ImageIcon[] icons = sd.getSpeakerIcons(); + Iterator textIter = textContent.iterator(); + boolean wasLastComponent = true; + while (textIter.hasNext()) { + Object nextContent = textIter.next(); + if (nextContent instanceof org.jdom.Text) { + String wylie = ((org.jdom.Text)nextContent).getText(); + dp.toTibetanMachineWeb(wylie, tDoc.getLength()); + wasLastComponent = false; + } + else if (nextContent instanceof org.jdom.Element) { + org.jdom.Element e = (org.jdom.Element)nextContent; + dp.setCaretPosition(tDoc.getLength()); + if (e.getName().equals("time")) { +/* if (!wasLastComponent) + try { + tDoc.insertString(tDoc.getLength(), "\n", null); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } +*/ + new TimePoint(dp, clockIcon, Integer.valueOf(e.getAttributeValue("t"))); + wasLastComponent = true; + } + else if (e.getName().equals("who")) { +/* if (!wasLastComponent) + try { + tDoc.insertString(tDoc.getLength(), "\n", null); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } +*/ + dp.insertComponent(new JLabel(" ", icons[Integer.parseInt(e.getAttributeValue("id"))], SwingConstants.LEFT)); + wasLastComponent = true; + } + } + } + currentWork = new Work(); + work.add(currentWork); + +if (keyboard_url != null) { + dp.registerKeyboard(keyboard_url); + // project.tName.setupKeyboard(); + // project.tTask.setupKeyboard(); + sharedDP.setupKeyboard(); + sharedDP2.setupKeyboard(); +} + +project.setTranscript(t); + + return true; + } catch (JDOMException jdome) { + jdome.printStackTrace(); + return false; + } +} + +class SpeakerManager extends JPanel { + JPanel top; + boolean isEditable; + +//public JPanel getSpeakerManager(final SpeakerTable sTable) { + +SpeakerManager(final SpeakerTable sTable) { + + setLayout(new BorderLayout()); + + JButton addButton = new JButton(messages.getString("Add")); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpeakerData sd = (SpeakerData)sTable.getModel(); + JPanel p0 = new JPanel(new GridLayout(0,1)); + JPanel p1 = new JPanel(); + p1.add(new JLabel(messages.getString("FaceColon") + " ")); + JComboBox combo = new JComboBox(sd.getSpeakerIcons()); + p1.add(combo); + JPanel p2 = new JPanel(); + p2.add(new JLabel(messages.getString("NameColon") + " ")); + sharedDP.setText(""); + sharedDP.setPreferredSize(new Dimension(250,50)); + p2.add(sharedDP); + p0.add(p1); + p0.add(p2); + if (JOptionPane.showConfirmDialog(SpeakerManager.this, p0, messages.getString("EnterNewSpeakerInfo"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) == JOptionPane.OK_OPTION) { + TibetanDocument doc = (TibetanDocument)sharedDP.getDocument(); + sd.addSpeaker(new Speaker(combo.getSelectedIndex(), doc.getWylie())); + } + } + }); + JButton editButton = new JButton(messages.getString("Edit")); + editButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int row = sTable.getSelectedRow(); + if (row == -1) + return; + SpeakerData sd = (SpeakerData)sTable.getModel(); + Speaker sp = sd.getSpeakerAt(row); + JPanel p0 = new JPanel(new GridLayout(0,1)); + JPanel p1 = new JPanel(); + p1.add(new JLabel(messages.getString("FaceColon") + " ")); + JComboBox combo = new JComboBox(sd.getSpeakerIcons()); + combo.setSelectedIndex(sp.getIconID()); + ImageIcon[] icons = sd.getSpeakerIcons(); + ImageIcon oldIcon = icons[sp.getIconID()]; + p1.add(combo); + JPanel p2 = new JPanel(); + p2.add(new JLabel(messages.getString("NameColon") + " ")); + sharedDP.setText(""); + sharedDP.setPreferredSize(new Dimension(250,50)); + sharedDP.toTibetanMachineWeb(sp.getName(), 0); + p2.add(sharedDP); + p0.add(p1); + p0.add(p2); + if (JOptionPane.showConfirmDialog(SpeakerManager.this, p0, messages.getString("EditSpeakerInfo"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) == JOptionPane.OK_OPTION) { + sd.setValueAt(new Integer(combo.getSelectedIndex()), row, 0); + TibetanDocument doc = (TibetanDocument)sharedDP.getDocument(); + sd.setValueAt(doc.getWylie(), row, 1); + if (!oldIcon.equals(icons[combo.getSelectedIndex()])) { + DefaultStyledDocument doc2 = (DefaultStyledDocument)pane.getDocument(); + int k = pane.getCaretPosition(); + for (int i=0; i -1 && JOptionPane.showConfirmDialog(SpeakerManager.this, messages.getString("SureDeleteSpeaker"), messages.getString("Warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { + SpeakerData sd = (SpeakerData)sTable.getModel(); + Speaker sp = sd.getSpeakerAt(row); + ImageIcon[] icons = sd.getSpeakerIcons(); + DefaultStyledDocument doc = (DefaultStyledDocument)pane.getDocument(); + int k2 = doc.getLength(); + for (int i=0; i 0) { + DefaultStyledDocument doc = (DefaultStyledDocument)tp.getDocument(); + AttributeSet attr = doc.getCharacterElement(pos-1).getAttributes(); + Component comp; + if (null != (comp = StyleConstants.getComponent(attr))) + if (comp instanceof JLabel) { + JLabel l = (JLabel)comp; + ImageIcon ic = (ImageIcon)l.getIcon(); + if (iconMap.containsKey(ic)) { + Speaker sp = (Speaker)iconMap.get(ic); + int k = speakers.indexOf(sp) + 1; + if (k == speakers.size()) + k=0; + try { + tp.getDocument().remove(pos-1, 1); + sp = (Speaker)speakers.get(k); + tp.insertComponent(new JLabel(" ", spIcon[sp.getIconID()], SwingConstants.LEFT)); + return; + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + } + } + Speaker sp = (Speaker)speakers.get(0); + tp.insertComponent(new JLabel(" ", spIcon[sp.getIconID()], SwingConstants.LEFT)); + } + }; + KeyStroke insertSpeakerKey = KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.ALT_MASK); + keymap.addActionForKeyStroke(insertSpeakerKey, insertSpeakerAction); + } + public boolean addSpeaker(Speaker speaker) { + if (iconMap.containsKey(spIcon[speaker.getIconID()])) + return false; + else { + iconMap.put(spIcon[speaker.getIconID()], speaker); + speakers.add(speaker); + fireTableRowsInserted(speakers.size()-1, speakers.size()-1); + return true; + } + } + public Speaker getSpeakerAt(int row) { + if (row > -1 && row < speakers.size()) + return ((Speaker)speakers.get(row)); + return null; + } + public java.util.List getSpeakers() { + return speakers; + } + public ImageIcon[] getSpeakerIcons() { + return spIcon; + } + public Speaker getSpeakerForIcon(Icon icon) { + if (iconMap.containsKey(icon)) + return (Speaker)iconMap.get(icon); + else + return null; + } + public void removeAllSpeakers() { + speakers.clear(); + iconMap.clear(); + } + public void removeSpeaker(int row) + { + if (row > -1 && row < speakers.size()) + { + Speaker sp = getSpeakerAt(row); + iconMap.remove(spIcon[sp.getIconID()]); + speakers.remove(row); + fireTableRowsDeleted(row,row); + } + } + public int getRowCount() + { + return speakers.size(); + } + public int getColumnCount() + { + return 2; + } + public Class getColumnClass(int c) + { + return getValueAt(0, c).getClass(); + } + public Object getValueAt(int row, int column) + { + Speaker sp = (Speaker)speakers.get(row); + if (column == 0) + return spIcon[sp.getIconID()]; + try { //otherwise column 1, the speaker name + return TibetanDocument.getTibetanMachineWeb(sp.getName().trim()); + } catch (InvalidWylieException iwe) { + iwe.printStackTrace(); + return null; + } + } + public void setValueAt(Object object, int row, int column) { + Speaker sp = (Speaker)speakers.get(row); + if (column == 0 && object instanceof Integer) { + Integer bigInt = (Integer)object; + int k = bigInt.intValue(); + if (!iconMap.containsKey(spIcon[k])) { + iconMap.remove(spIcon[sp.getIconID()]); + iconMap.put(spIcon[k], sp); + sp.setIconID(k); + } + } else if (object instanceof String) { + String wylie = (String)object; + sp.setName(wylie); + } + fireTableCellUpdated(row, column); + } +} + +class SpeakerTable extends JTable +{ + private TableCellRenderer duffRenderer, normalRenderer; + private SpeakerData speakerData; + + public SpeakerTable(SpeakerData speakerData) + { + this.speakerData = speakerData; + this.setModel(this.speakerData); + this.setRowHeight(55); + this.setColumnSelectionAllowed(false); + this.setRowSelectionAllowed(true); + + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + TableColumnModel tcm = this.getColumnModel(); + duffRenderer = new DuffCellRenderer(); + + TableColumn tc = tcm.getColumn(0); + tc.setResizable(false); + tc.setMaxWidth(60); + tc.setMinWidth(60); + tc.setHeaderValue(messages.getString("Face")); + + tc = tcm.getColumn(1); + tc.setCellRenderer(duffRenderer); + tc.setHeaderValue(messages.getString("Name")); + } +} + +public JMenuBar getTextMenuBar() { + JMenu modeMenu = new JMenu(messages.getString("Mode")); + JRadioButton editButton = new JRadioButton(messages.getString("Edit")); + JRadioButton viewButton = new JRadioButton(messages.getString("ReadOnly")); + editButton.setActionCommand("edit"); + viewButton.setActionCommand("view"); + RadioListener l = new RadioListener(); + editButton.addActionListener(l); + viewButton.addActionListener(l); + editButton.setSelected(true); + ButtonGroup bg = new ButtonGroup(); + bg.add(editButton); + bg.add(viewButton); + JPanel buttons = new JPanel(new GridLayout(0,1)); + buttons.add(editButton); + buttons.add(viewButton); + modeMenu.add(buttons); + + JMenu viewMenu = new JMenu(messages.getString("View")); + JMenuItem previousItem = new JMenuItem(messages.getString("Previous")); + JMenuItem currentItem = new JMenuItem(messages.getString("Current")); + JMenuItem nextItem = new JMenuItem(messages.getString("Next")); + JMenuItem suppressTimesItem = new JMenuItem(messages.getString("SuppressTimes")); + viewMenu.add(previousItem); + viewMenu.add(currentItem); + viewMenu.add(nextItem); + viewMenu.addSeparator(); + viewMenu.add(suppressTimesItem); + + JMenu searchMenu = new JMenu(messages.getString("Search")); + JMenuItem findTextItem = new JMenuItem(messages.getString("FindText")); + findTextItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + findText(); + } + }); + + JMenuItem replaceTextItem = new JMenuItem(messages.getString("ReplaceText")); + replaceTextItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + replaceText(); + } + }); + + JMenuItem findspeakerItem = new JMenuItem(messages.getString("FindSpeaker")); + JMenuItem findtimeItem = new JMenuItem(messages.getString("FindTime")); + searchMenu.add(findTextItem); + searchMenu.add(replaceTextItem); + searchMenu.addSeparator(); + searchMenu.add(findspeakerItem); + searchMenu.add(findtimeItem); + + editMenu = new JMenu(messages.getString("Edit")); + JMenuItem cutItem = new JMenuItem(messages.getString("Cut")); + JMenuItem copyItem = new JMenuItem(messages.getString("Copy")); + JMenuItem pasteItem = new JMenuItem(messages.getString("Paste")); + JMenuItem selectallItem = new JMenuItem(messages.getString("SelectAll")); + JMenuItem insertspeakerItem = new JMenuItem(messages.getString("InsertSpeaker")); + JMenuItem insertonetimeItem = new JMenuItem(messages.getString("InsertOneTime")); + JMenuItem inserttwotimesItem = new JMenuItem(messages.getString("InsertTwoTimes")); + editMenu.add(cutItem); + editMenu.add(copyItem); + editMenu.add(pasteItem); + editMenu.add(selectallItem); + editMenu.addSeparator(); + editMenu.add(insertspeakerItem); + editMenu.add(insertonetimeItem); + editMenu.add(inserttwotimesItem); + + JMenuBar bar = new JMenuBar(); + bar.add(modeMenu); + bar.add(viewMenu); + bar.add(searchMenu); + bar.add(editMenu); + return bar; +} + +public int findNextText(int startPos, TibetanDocument sourceDoc, TibetanDocument findDoc) { + if (startPos<0 || startPos>sourceDoc.getLength()-1) + return -1; + +try { + + AttributeSet firstAttr = findDoc.getCharacterElement(0).getAttributes(); + String firstFontName = StyleConstants.getFontFamily(firstAttr); + char firstSearchChar = findDoc.getText(0,1).charAt(0); + + boolean match = false; + for (int i=startPos; i0) { //found!! so highlight text and seek video + if (startingOver && i>pos.getOffset()-1) + break; + pane.setSelectionStart(i); + pane.setSelectionEnd(i+findDoc.getLength()); + if (JOptionPane.showInternalConfirmDialog(textFrame, messages.getString("FindNextYesNo"), null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) != JOptionPane.YES_OPTION) + break; + i++; + } + if (i<0 || i==doc.getLength() && pos.getOffset()>0) { //reached end of document - start over? + if (startingOver || pos.getOffset()==0) + break; + if (JOptionPane.showInternalConfirmDialog(textFrame, messages.getString("StartFromBeginning"), null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) != JOptionPane.YES_OPTION) + break; + i=0; + startingOver = true; + } + } + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + + } +} + +public void replaceText() { + //get input from user on what to search for + JPanel p0 = new JPanel(new GridLayout(0,1)); + JPanel p2 = new JPanel(); + p2.add(new JLabel(messages.getString("FindWhat") + " ")); + if (findDoc == null) { + sharedDP.setText(""); + findDoc = (TibetanDocument)sharedDP.getDocument(); + } else + sharedDP.setDocument(findDoc); + sharedDP.setPreferredSize(new Dimension(250,50)); + p2.add(sharedDP); + JPanel p3 = new JPanel(); + p3.add(new JLabel(messages.getString("ReplaceWith") + " ")); + if (replaceDoc == null) { + sharedDP2.setText(""); + replaceDoc = (TibetanDocument)sharedDP2.getDocument(); + } else + sharedDP2.setDocument(replaceDoc); + sharedDP2.setPreferredSize(new Dimension(250,50)); + p3.add(sharedDP2); + + p0.add(p2); + p0.add(p3); + + if (JOptionPane.showConfirmDialog(textFrame, p0, messages.getString("FindReplaceHeading"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) == JOptionPane.OK_OPTION) { + + try { + java.util.List replaceDCs = new ArrayList(); + for (int k=0; k0) { //found!! so highlight text and seek video + if (startingOver && i>pos.getOffset()-1) + break; + if (replaceAll) { + doc.remove(i,findDoc.getLength()); + doc.insertDuff(i,dd); + } else { + pane.setSelectionStart(i); + pane.setSelectionEnd(i+findDoc.getLength()); + String choice = (String)JOptionPane.showInternalInputDialog(textFrame, messages.getString("ReplaceQ"), null, JOptionPane.PLAIN_MESSAGE, null, replaceOptions, replaceOptions[0]); + if (choice == null) //cancel, so stop searching + break outer; + if (choice.equals(replaceOptions[0])) { //replace + doc.remove(i,findDoc.getLength()); + doc.insertDuff(i,dd); + } + else if (choice.equals(replaceOptions[1])) { //replace all + doc.remove(i,findDoc.getLength()); + doc.insertDuff(i,dd); + replaceAll = true; + } + } + i++; + } + if (i<0 || i==doc.getLength() && pos.getOffset()>0) { //reached end of document - start over? + if (startingOver || pos.getOffset()==0) + break; + if (JOptionPane.showInternalConfirmDialog(textFrame, messages.getString("StartFromBeginning"), null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) != JOptionPane.YES_OPTION) + break; + i=0; + startingOver = true; + } + } + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + + } +} + +class RadioListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("edit")) { + //make the text pane editable + pane.setEditable(true); + + //reinstate the edit menu to the pane + textFrame.getJMenuBar().add(editMenu); + textFrame.invalidate(); + textFrame.validate(); + textFrame.repaint(); + + //add speaker-edit features + spm.setEditable(true); + + //add the time-coding tab + if (tcp != null) + jtp.addTab(messages.getString("TimeCoding"), tcp); + + //make the project details editable + if (project != null) +// project.setEditable(true); + + jtp.addTab(messages.getString("ProjectDetails"), project); + } + else if (e.getActionCommand().equals("view")) { + //make the text pane non-editable + pane.setEditable(false); + + //remove the edit menu from the pane + textFrame.getJMenuBar().remove(editMenu); + textFrame.invalidate(); + textFrame.validate(); + textFrame.repaint(); + + //remove speaker-edit features + spm.setEditable(false); + + //remove the time-coding tab + if (tcp != null) + jtp.remove(tcp); + + //make the project tab non-editable + if (project != null) + jtp.remove(project); +// project.setEditable(false); + } + } +} + + private class XMLFilter extends javax.swing.filechooser.FileFilter { + // accepts all directories and all savant files + + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String fName = f.getName(); + int i = fName.lastIndexOf('.'); + + if (i < 0) + return false; + + else { + String ext = fName.substring(i+1).toLowerCase(); + + if (ext.equals("xml")) + return true; + else + return false; + } + } + + //the description of this filter + public String getDescription() { + return "Extensible Markup Language (.xml)"; + } + } +} diff --git a/source/org/thdl/quilldriver/QDPlayer.java b/source/org/thdl/quilldriver/QDPlayer.java new file mode 100644 index 0000000..5c061df --- /dev/null +++ b/source/org/thdl/quilldriver/QDPlayer.java @@ -0,0 +1,405 @@ +package org.thdl.quilldriver; + +import java.util.*; +import java.net.*; +import javax.media.*; +import java.awt.*; +import javax.swing.*; +import javax.swing.event.*; + +/*-----------------------------------------------------------------------*/ +public class QDPlayer extends Panel implements ControllerListener +{ + private EventListenerList listenerList = new EventListenerList(); + + public URL mediaURL; + + private Vector orderStartID, orderEndID; + private Stack pileStart, pileEnd; + private Hashtable hashStart, hashEnd; + + private Player player = null; + private Component visualComponent = null; + private Component controlComponent = null; + private Panel panel = null; + private JPanel vPanel = null; + + private Container parent = null; + + private java.util.Timer timer = null; + private Time stopTime = null; + private Time pauseTime = null; + private boolean stillLoadingVideo = false; + private boolean isMediaAudio = false; + private boolean isSized = false; + + private Float to = null; +/*-----------------------------------------------------------------------*/ + public QDPlayer(Container p, URL sound) { + parent = p; + makeMedia(sound); + } + public void makeMedia(URL sound) { + if (mediaURL != null) { + cmd_stop(); + destroy(); + } + mediaURL = sound; + start(); + } + public URL getURL() { + return mediaURL; + } + public void destroy() { + player.close(); + } + public void start() { + openPlayer(); + } + public Component popVisualComponent() + { + vPanel.remove(visualComponent); + invalidate(); + validate(); + repaint(); + return visualComponent; + } + public void restoreVisualComponent() + { + vPanel.add("Center", visualComponent); + invalidate(); + validate(); + repaint(); + } + public Component getVisualComponent() + { + return visualComponent; + } + public Component getControlComponent() + { + return controlComponent; + } +/*-----------------------------------------------------------------------*/ + public boolean cmd_isSized() { + return isSized; + } + public boolean cmd_isRealized() { + return player.getState() == Controller.Realized; + } + public String cmd_firstS() { + return (String)orderStartID.elementAt(0); + } + public boolean cmd_stop() { + if (player == null) + return false; + try { + player.stop(); + return true; + } catch (NotRealizedError err) { + System.out.println("NotRealizedError"); + return false; + } + } + public boolean cmd_isID(String theID) { + System.out.println(hashStart.containsKey(theID)); + return hashStart.containsKey(theID); + } + public boolean cmd_play() { + if (stillLoadingVideo || player == null) + return false; + if (player.getState() == Controller.Started) + return true; + + if (pauseTime == null) + player.setMediaTime(new Time(0.0)); + else + player.setMediaTime(pauseTime); + if (player.getTargetState() < Player.Started) { + player.setStopTime(Clock.RESET); + player.prefetch(); + } + player.start(); + return true; + } + public boolean cmd_playFrom(Integer from) { + if (stillLoadingVideo) + return false; + if (play(from, null)) + return true; + else + return false; + } + public boolean cmd_play(Integer from, Integer to) { + if (stillLoadingVideo) + return false; + if (play(from, to)) + return true; + else + return false; + } +/*-----------------------------------------------------------------------*/ + public int getLastTime() { + Time t = player.getDuration(); + long l = t.getNanoseconds(); + return new Long(l / 1000000).intValue(); + } + public int when() { + if (player == null) + return -1; + if (player.getState() < Controller.Realized) + return -1; + long currTime = player.getMediaNanoseconds(); + return new Long(currTime / 1000000).intValue(); + } + private boolean play(Integer from, Integer to) { + if (player == null) + return false; + + final Time startTime = new Time(from.longValue() * 1000000); + try { + if (player.getState() == Controller.Started) + player.stop(); + while (player.getState() == Controller.Unrealized) + ; + +// player.stop(); + if (to == null) { + stopTime = null; + player.setStopTime(Clock.RESET); + } else { + stopTime = new Time(to.longValue() * 1000000); + player.setStopTime(stopTime); + } + player.setMediaTime(startTime); + player.prefetch(); + player.start(); + return true; + } catch(NotRealizedError err) { + System.out.println("NotRealizedError"); + return false; + } + } +/*-----------------------------------------------------------------------*/ + public void openPlayer() { + try { + player = Manager.createPlayer(mediaURL); + player.addControllerListener(this); + } catch (javax.media.NoPlayerException e) { + System.err.println("noplayer exception"); + e.printStackTrace(); + return; + } catch (java.io.IOException ex) { + System.err.println("IO exception"); + ex.printStackTrace(); + return; + } + if (player != null) + player.realize(); + } + public synchronized void controllerUpdate(ControllerEvent event) { + if (player == null) + return; + if (event instanceof RealizeCompleteEvent) { + System.out.println("received RealizeCompleteEvent event"); + if (visualComponent == null) { + if (panel == null) { + setLayout(new GridLayout(1,1)); + vPanel = new JPanel(); + vPanel.setLayout( new BorderLayout() ); + if ((visualComponent = player.getVisualComponent())!= null) + vPanel.add("Center", visualComponent); + else { + isMediaAudio = true; + stillLoadingVideo = false; + } + if (!stillLoadingVideo) + { + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + } + add(vPanel); + } + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + isSized = true; + if (stillLoadingVideo) + player.start(); + } else if (event instanceof StartEvent) { + StartEvent se = (StartEvent)event; + Time t = se.getMediaTime(); + long longt = t.getNanoseconds(); + Float from = new Float(longt); + float f = (from.floatValue() / 1000000000); + from = new Float(f); + t = player.getStopTime(); + longt = t.getNanoseconds(); + to = new Float(longt); + f = (to.floatValue() / 1000000000); + to = new Float(f); + if (timer != null) + { + timer.cancel(); + timer = null; + } + timer = new java.util.Timer(true); + timer.schedule(new TimerTask() { + public void run() { + //this is specifically for the MPG stop time bug + if (stopTime != null) + if (player.getMediaTime().getNanoseconds() > stopTime.getNanoseconds()) + player.stop(); + }}, 0, 15); + } else if (event instanceof StopEvent) { + pauseTime = player.getMediaTime(); + + + /*messy problems require messy solutions: + if the slider is present, dragging it while playing creates + a RestartingEvent, and if I set the media time here it messes up + and barely plays at all (maybe because it cancels the previously + set media time? - I don't know). + + but it seems that if you press the play/pause button on the + control widget, then you need to set the media time upon stop + (probably because of problem noted below, namely that you get + weird results if you do player.start() without setting the media + time.*/ + + if (!(event instanceof RestartingEvent)) + player.setMediaTime(pauseTime); + +// player.setStopTime(Clock.RESET); + stopTime = null; + + System.out.println("received StopEvent"); + + if (timer != null) + { + timer.cancel(); + timer = null; + } + if (stillLoadingVideo) + { + System.out.println("received EndOfMediaEvent"); + stillLoadingVideo = false; + player.stop(); + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } else if ( event instanceof CachingControlEvent) { + CachingControlEvent e = (CachingControlEvent) event; + System.out.println("got CachingControlEvent: " + e); + if (!isMediaAudio) + stillLoadingVideo = true; + } else if (event instanceof ControllerErrorEvent) { + player = null; + System.err.println("*** ControllerErrorEvent *** " + ((ControllerErrorEvent)event).getMessage()); + } else if (event instanceof PrefetchCompleteEvent) { + if (panel != null) { + panel.invalidate(); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } +}; + +/* + +After pause the MPEG video and playing it again it gets faster +Author: vladshtr +In Reply To: After pause the MPEG video and playing it again it gets faster +Mar 1, 2001 6:25 PM + +Reply 1 of 1 + + +The problem is in the setting the Meida time. + +The safety way is to always set new media time with the +following method: setMediaTime(Time time); .... if you want to +use it after +-player.stop(); used as real stop you can use setMediaTime(new +Time(0.0)); +-player.stop(); used as real pause you have to use the +combination: +player.stop(); +Time currentTime = player.getMediaTime(); +//........ +player.setMediaTime(currentTime); +player.start(); + + +Re: (urgent) when you pause and resume, video plays at rate > 1 +Author: seertenedos +In Reply To: (urgent) when you pause and resume, video plays at rate > 1 +Aug 11, 2002 11:36 PM + +Reply 1 of 1 + + +I found a solution for this problem for those that are interested. + +what you have to do is store the time just before you pause and then set the +time just before you play. here is a copy of my pause and play methods + +// Start the player +private void play() { +if (player != null) +{ +if (pauseTime != null) +{ +player.setMediaTime(pauseTime); +} +if (player.getTargetState() < Player.Started) +player.prefetch(); +player.start(); +} +} + +// Pause the player +private void pause() { +if (player != null) +pauseTime = player.getMediaTime(); +player.stop(); +} + + +that should solve your pause play problems! + +> The problem is below. It seems quite a few people are +> having this problem but i have not seen a solution +> around. I really need a solution to this problem as +> the whole point of my application is that it plays +> divx and mpeg videos. At the moment i have divx +> movies playing through the mpeg demuxer as the avi one +> stuffed up the audio. I think that is the reason it +> affects both divx and mpeg. My application is due in +> one week and my client is not going to be very happy +> if this problem happens every time they pause then +> play the video. +> The player is for divx movies. If anyone knows how to +> solve this problem or how to make it so you can pause +> and resume divx movies please respond. +> +> Pause and Resume playback. +> The video plays at a high rate and there is no audio. +> Problem doesn't appear while seeking. +> +> +> +> + +*/ \ No newline at end of file diff --git a/source/org/thdl/quilldriver/QDShell.java b/source/org/thdl/quilldriver/QDShell.java new file mode 100644 index 0000000..0c33cb8 --- /dev/null +++ b/source/org/thdl/quilldriver/QDShell.java @@ -0,0 +1,159 @@ +package org.thdl.quilldriver; + +import java.io.*; +import java.awt.*; +import java.net.*; +import java.util.*; +import javax.swing.*; +import java.awt.event.*; +import javax.swing.text.*; +import javax.swing.text.rtf.*; + +public class QDShell extends JFrame { + ResourceBundle messages = null; + QD qd = null; + +public static void main(String[] args) { + try { + PrintStream ps = new PrintStream(new FileOutputStream("qd.log")); + System.setErr(ps); + System.setOut(ps); + } + catch (Exception e) { + } + + Locale locale; + + if (args.length == 2) { + locale = new Locale(new String(args[0]), new String(args[1])); + Locale[] locales = Locale.getAvailableLocales(); + for (int k=0; kgwu>ijMsJ{L9PB+1c4jN>B6i@-;O}ZEbKOA~UtM zwWg-1b#6Nl9P^zK;83_Q2Bs7o-O4JEu0~E$P@W_H!mhcMD@Og-Y0F4F!7ywqb ztO*RbJ z++l&97(pDY#AreTH4I;5ED)t3fP^Xp)&dxSAb}YNFLI7*-M|G5mm^By>~^QZgdt2q ze((_Z3xXPmEN1hNS40I17fRy&u)z|O102+Gv1q{|I1DBY0if_PLBIe?n3y~alR>2= zFt%uz@`dID$P{FA5+c|2u}c6Rz>*b%2A75L!2lCnfZGHJ943GVdlW{0U$?OCd2OG3$*8s7pXhH}8 EJ9=ax_W%F@ literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face01a.jpg b/source/org/thdl/quilldriver/face01a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b363984a10b3bae5dc6be971c5e775d8d582a21 GIT binary patch literal 992 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<Nw5*fhOn|QvN13NrE~-t7@1gDm^tCH zj0`|i1V1PmItB_Q7P1OAF5GzV;=_+3%KvXM@Gt{q1(^jI>>2hy+q3HOlP8aUbjoov ziA;ODRW-`uepSTzm;Ii%D+AZf-}uTS{kgO@f9Lh@so|RX_pP-qeYE1Yof4ML+qE`w zy?0l)cHNPWtEIUn*-Y|y)x3M&-5X^$WY;mKP-fJFXb^zTzmg6$CI$-6Q72>xFIhc{AVM} zG6B!f4^Ma}Zd_zm&9`5LN#aI3rR6)X&E#~y_@(r1mF$uP=RR+4o`~6( z9!-lsJ1=|6(>C=UxBHS|3Cxq;N;B{`_`klsH1VjQ);9sG{-nI_=Tg?*8i)J4e7`Je zWUX#}&oVjQVxRs5)71waoSx9@XuRRCn}_ma*?;$MyT^yBF6)*&d$4JHUGyqNr_7_z zrk9C{*4{nzeC0oWlVc?(*rqEx8E^UIsc}2yKSS#`=Nw+yYJn-uniueh7R-%>Fn z@9(#$-{t2G?vz`0Jes;GY;Dq;W7#^BLQ@0t*RZCtFs=Hn&|ob$sru`QEA7k^gQrcL L;rDNA(*K(PNK$~? literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face02a.jpg b/source/org/thdl/quilldriver/face02a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..715ee5e68e7f79f771cd2dcdd7f82dc484bee3e9 GIT binary patch literal 3653 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 literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face06a.jpg b/source/org/thdl/quilldriver/face06a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b830bda3b16e273c2043f56801aa69ecd081579 GIT binary patch literal 4358 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 sNRPH+AH7h~Zn6)hQMDB`SNFx)JL5ANa(w(EtDd literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face07a.jpg b/source/org/thdl/quilldriver/face07a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..810bdf3c95d15f11f66e1afd2085222038e48e8e GIT binary patch literal 3835 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 T;(U3%BK9bIrz4|hF4X!j?=Q2X literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face08a.jpg b/source/org/thdl/quilldriver/face08a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45e67a56b939cb2991305aa171aa85aec7218977 GIT binary patch literal 1647 zcmb7;YgCg37{}keyN@v$8|Gl#?+7H@9D>|79I;nHb^#GW8&DiEkd2EPrjkNvFb}8?!C+WB`}l97`FYYAw095~7K_Cj;nx`(ucO&gZE62IhHij}0o(vLIE)B@L>Qb1 zGxPx#004q;81Qf4NB|8YFsRif!vuiA;RpZ$qOpG$U?3cUL=gc~TQ3sXj)mr}rSV1L z9F3U+oypGpR=u!#MS%hTB?7BR5b@6DwQ7dJR~Z=eKSCG?z=^g9FH@G7#LKBhl4)#F zv3kLd&TqN>aM3UU;8&jmiEtti2yip+?;!8(Y3((eDc{!S^Vk+6*FpTXK>)m)x@W{K zl*i?@?&Q~gX|s-VU&=YJ7Ak8x^&u>`OkOfBATB^1>Wp|qO(fm4k7SJJub7~@Y5kMs z*Gevxe__TEmv_w2CLo#VTRIgRZ9_e}9g&2{Hpvu+mr)|tgwo~@F+?$y`)}7Pyfr85 z+W5JCbp!I5PNoEm>N;@avnSR8nSC+a-tY0NFCE=|pzrFoIl?0C}}-d{Cs z?GkYN?eO%h=t*KsMpBhH)%Wq*wW_8mh!^BgGRM^<*WBpd-=FckCOtRaJUNj3gdP1N zFj}nA>Evg^=X<}NE`ajR6}8`UzYdi)DsWky>etMn1|QsJRsIk%#VMwCDNpt*YAV+O zU&Tcn|GE}fEID=f+Yj$n9Q(AtFgWz6LO0QGZdvBkj5&PMeJcFS@lzdL^ycHwu)&St z60>%>hik;(JZ0>RhPn|xHqy~C^?9(g42u4-;D&hg(BVaUA*8QZY;Mm_d2K9L4nq)M zx4A?`{i3!N`BD1dI){XqGrQSJGw+r*k1pr_q{j0~4y%2jN_&=eDM}$f*z(}QwJi#iQzBqdXted?o^fwJ-FKH}C9K*2>?>ShOo#0oPQ9?N;Tb`8 zl6;*W;1t!+*DDpwI*!}RV6mLBdWh?nn0-v^m#$`BxeS5jpZ+AReVUZPI57KO+^Bvb zuusIl?5wy_Cck*e$87xPbW^^)Yn@M}zR~Srn51^vrgAb=XHrisO5f8Us1x%F=y}hl zPRxmJoy~9ca7XPDX6?+5KlxP$N#(fvP6suSaFnvioK#-qV|+pH=vckQ4{r9PL_39immEm^E`Vj%=l8gxXbxj>5N7i(9kHyagOVqPh zUwXbd#N0Egy_}GXN}%P%-jih20rVwfj4W*UB4C6K9w=m1ElPj*GFnXN_-)tLEk`Kz zo5;9>>cOYWO~<5ZaoOvqBaXGehe)^8CH(Q<0_7#Dx;j)Fat@v4$LMHmcqg|;j0eFiCizVxopa?HkUGJT?gILj5g z@E2mSyql?(z1DlBtwQ7=>-(~M2+M{H(Za-F5=D6AHs@E8j+bQr5}ihadNaO~b{moRR*+>@xK)R96e@q6tzKbTs*y|tN;(1c%KPsqoCT5#c; zk5avJDpLiXvJ*v*!UVDtf=fXQ1Nm8nO@FvNC7cck33BE<+x5zhxAE7rR;2dHP0O7R z2YTLALXF$vl{E6+Aklux^dYTn>-5C3Zg2xRBf8#GJjcMU#AajfCqUNuO7WEn=Q8D<{U8rA7f-L~$w~ z=3iy^V0x6$o8Y@%XyLUqQYyr4WU`9EVsQQA6i+V-hG*@bQ<)~)e=6ydR|StOB~f8q Lhf&!P!`;6CP5Z38 literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face09a.jpg b/source/org/thdl/quilldriver/face09a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df0121ef59e8d3a2208006293c269ee6065c426f GIT binary patch literal 2872 zcma)730PCd7M`1gB!sX8f-F+GYB1`vSY@&3(}>8fbzu`J)sS3B1QN&sq6J>nzN)QO zf{HBS0*VUN0s>zG{Y_i^WZ=fpgtFQ0e@64S!bIzQ9=6v%HT8lOV z9Tx{@2LKTu;DmhueMNb?Ss<2)r2=sXY+?Qx_Dh`s%gkllyr-LI`tvCJ0y-1pd4%=YIAh91e2;LwJ5Xgk00N7R(5QN|{BuwY1 z{ET$p``HG`gfcmQrU$WKV`}#fLEHc-7N?FcfD5EL9TH8;P8<>;!E?a4&(xG^j;+IV z;f8QUh!lZmE&^!p_D@jlYQSWpSS02NB;sHMcH##4%fuoCc0*)1a6B#01y-u0pJFW; zHvmW#Is9RyyM!x}`XiDVktSGW|5Aw0z|kErtK;45QwT|1@I9&m5C+rI<6EiGrkAaDU#^= zUm)SImr%qPhf861fjrnx#1#f%F6Ouortq}x1b~ipNxHxgK}dNeB>#e@^NEhy)P{B!U`+OjRS&EwD)jku+C#nVRhuuHL-RZ8QIC=$ye;1dQS6b6G%m4%ehL)tlL?NqL zsUXZAN+Z1&E$zENqZWfwHH=h zEa2FW51MWoNj;7N^x<<9FzF4MFV1ES?P=|)T44fwg}XUtd7o&84MlRikTr4X2ny0` zg0B>gRD4M#uD7`v(MkYAZu>z*~N=#TL+{%wC*S-uBV$Fwm#x<+!zKZKk&ppF?-4wXEBCV?8-tEdAgOLx8c%7>Xt#yu! zv#Ie7e36^?%bkh%qXk3XXZ+rno95Z%i-L;LsJJw*6pt?pJw~%@EY@TWJU!dxwKpVz zcJy0-D92~-x3H^jYLRkbXoPI$)uq%e~ z69C%47JC}Szz-uv7;FXttS`e}vb!%HJX8HB9B>Vcz>@3|B=d*ayVypG+*pzH*19!gcuCkT7V81%e(CEN%dxzBP zo{u~h8oz1l$C(3>e|utzJw8GnpF3?6>^^wv(vADI&)zPwarPEQ9E!i3Usl&WvUsJ- z_Fa1pCtSH%UjKX)yX928WE>FRym6DqBUz&Or{`W8!NK?0m+qWyc)2*kb$;P14z(?I z`0EZ7$lE!a$7`~)ZwMYaD)xq@`}k`7yiah&)8@&Vbhg&l(Gl90=QsTJ+{bmSw!JJl z@v?9<_l(wsix1d2NsPkczWcW#eS~ct>o*12c7xum zqi@RllfFvq9W-YRWu_X-k7Usnm#}z6DNFh%C%ui#jb29vv|nRiW5umW<9K?T4YFcU zWqga^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<&=!fQlIyS%FeYKns}} zn3xz@;no065(Jr|#9{>17(^Ge|9DOY|dnYo0fZf996P{-SFVEO65>(>lsoGF!j8@z*?vz}v9 z|10N18^5vVS>EdKewWH`w%laq))1DJ+KNxBsy@E$&aM_YnYPK7@xej8U%{r6bapar zd(1N}Wxw7wwfhMh zi>lU{Z9KE(>uc_v8uz!BDSTzW{qM22@e-p|ckbu3Kb2*eRoB#Qv2?{p!MD6lyDPgt zIj{J#ou%yY+OsQ`#U_h>6p6yOPrfTJvtF#s=UHZa z#^l!tl@r-&vkm_`+;ul7OY42(P{5yfq3_Y3KEo5|KAV*zOB09k3X46T z`3-wwznshXTJn~q_4LB$2|Hi@S({h!_HCz5zgVcx*MxJPyxc}_b)+ZR8f@&{VPhSf zE~L?O?)+AcTM<7U_P)u#5-)usaN}aeii-%Px**VdmnA- zI`izu5A}(ezwSDRUHOvecCfsBZ~KDBJKq@iKG4iue)&b!U&-ZR`?4Zlv8?0y8hCe) z+$oOj+~?z-{7DphKWSA=(*6XVW&=Zax$}ZE7>+O4C%D7*&vi$Gmt8rhHO>U>OIy}t z-lwT0$}G`s&KJI`IlJ*}AD_@kMyr23zR^FtBZGVbGhb#Y+Z@#iWzJcAML4_mwy0(L M6t{)@`2XJo0F4S^1poj5 literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face11a.jpg b/source/org/thdl/quilldriver/face11a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ed1744658bfe1f34c42c919388ac16ed407b9e5 GIT binary patch literal 5043 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 literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face12a.jpg b/source/org/thdl/quilldriver/face12a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e13b3c732504a7895f083d80b0fb7399e521b66e GIT binary patch literal 3748 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 EH&?-NrT_o{ literal 0 HcmV?d00001 diff --git a/source/org/thdl/quilldriver/face13a.jpg b/source/org/thdl/quilldriver/face13a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62e1a8548c643d96a184378a5b9bef0cdf13994b GIT binary patch literal 1249 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<C(E84!S#jh%&oi5VzoA;7@M z%*4XX%*oCQk!NILW?>a%U=valHgseUOcW7SGAk@;+;qt(D0JfFDGQaIiZ>nv>J$a} z9~FQs6A?rgW%z%Kfd}XSCP8LF2787JUELdvxQs=e)&@rJkxkVoQPEAAFr{&M_Ur^T z{gC2msR>L^{bGtloT6D2x?h@aU4JLPtI@k^%K_e%r)H;aUhcP@ZPMiI=%pRon7Sut zgfD6rFpq7Vpp2xIX$UzI{Y_@OMO=OkFEY+k6&)u`E2Sx-Qd54Umge) zFH2nebk{A#;8&ZtwG;K`8F-yNsXTXQj$z=_nF5b?ODtW6SazJG@dMO`#ygMaogy~}iVDrNkq;j%4@gSY!#z=EKK zd2f$DecWKF7C!05%Jw^so~pjear3!(-@jpJykzSpvwX^7BZ1|UYklQilkWT#-p3Sp zYx-KB-;3;0A1%(UGg(vt>Ap7%o1Mxm`)9~b zICI5PbtYF})_IdnTb4R#{b^7Ue0b_Hi)GlWAkBhFe=7J+t0rH!5yDYH|7FdH{|SKrSdB$vI!Vn@MJ_RNC$6?;DOuk?~@>SS5- zS*z%1nAs-t=S>o;|1Q3`(r`vdy3LLgR~UO9<=tJQm;d&kLExT^YV*zYj!gCLeeyBZ zQ!}Sqz)|7;o;$L?9;oeIS#{<7F6C!&S{gHrubc}1VgK?-7}tlzn?p3F2jxkx*W~u@ zwGet!o|~|{)Tx1?xp2e2V-IY#MD2tYU(Wt=Ox?58)kn+fg1}1;wO?Ti0w15rKfjE* z#!9Aqk!GmI#CiHlts)e3w?&CxxK)+Id-9d%%N(XZ|4tb_Ioj$TvLg0nYNDr|S?Jq_ z{AHJKEDcr;e$>jQyiM9|adG06d4E_IZ`F^Q`Q4@F^ifway_jXjlG|=&K2hMEG*hp^ zPHH2|ben^TwhK9Sg)H-uV$nUSapQLO 0) { + int num = getMinusStart(saveOrder); + orderStartID.addElement(saveOrder.elementAt(num)); + saveOrder.removeElementAt(num); + } + saveOrder = new Vector(); + for (Enumeration e = hashEnd.keys() ; e.hasMoreElements() ;) { + Object o = e.nextElement(); + saveOrder.addElement(o); + } + orderEndID = new Vector(); + while (saveOrder.size() > 0) { + int num = getMinusEnd(saveOrder); + orderEndID.addElement(saveOrder.elementAt(num)); + saveOrder.removeElementAt(num); + } + } + public void destroy() { + player.close(); + } + public void stop() { + player.stop(); + player.deallocate(); + } + public void start() { + openPlayer(); + } + private int getMinusStart(Vector v) { + int index = 0; + String first = (String)v.elementAt(index); + Float minus = (Float)hashStart.get(first); + for (int i=0;i f.floatValue()) { + minus = f; + index = i; + } + } + return index; + } + private int getMinusEnd(Vector v) { + int index = 0; + String first = (String)v.elementAt(index); + Float minus = (Float)hashEnd.get(first); + for (int i=0;i f.floatValue()) { + minus = f; + index = i; + } + } + return index; + } + public void addAnnotationPlayer(AnnotationPlayer ap) + { + listenerList.add(AnnotationPlayer.class, ap); + } + public void removeAnnotationPlayer(AnnotationPlayer ap) + { + listenerList.remove(AnnotationPlayer.class, ap); + } + public Component popVisualComponent() + { + vPanel.remove(visualComponent); + invalidate(); + validate(); + repaint(); + return visualComponent; + } + public void restoreVisualComponent() + { + vPanel.add("Center", visualComponent); + invalidate(); + validate(); + repaint(); + } + public Component getVisualComponent() + { + return visualComponent; + } + public Component getControlComponent() + { + return controlComponent; + } +/*-----------------------------------------------------------------------*/ + public boolean cmd_isSized() { + return isSized; + } + public boolean cmd_isRealized() { + return player.getState() == Controller.Realized; + } + public String cmd_firstS() { + return (String)orderStartID.elementAt(0); + } + public boolean cmd_stop() { + if (player == null) + return false; + try { + player.stop(); + return true; + } catch (NotRealizedError err) { + System.out.println("NotRealizedError"); + return false; + } + } + public boolean cmd_isID(String theID) { + System.out.println(hashStart.containsKey(theID)); + return hashStart.containsKey(theID); + } + public boolean cmd_playFrom(String fromID) { + if (stillLoadingVideo) + return false; + + Float from = (Float)hashStart.get(fromID); +// String toID = (String)orderEndID.elementAt(orderEndID.size()-1); +// Float to = (Float)hashEnd.get(toID); + + if (play(from, null)) + return true; + else + return false; + } + + public boolean cmd_playS(String fromID) { + if (stillLoadingVideo) + return false; + + Float from = (Float)hashStart.get(fromID); + Float to = (Float)hashEnd.get(fromID); + if (play(from, to)) + return true; + else + return false; + } + public void cmd_nextEvent() { + Float when = new Float(when()); + if (!pileStart.empty()) { + String id = (String)pileStart.peek(); + Float f = (Float)hashStart.get(id); + if (when.floatValue() >= f.floatValue()) { + id = (String)pileStart.pop(); + fireStartAnnotation(id); + } + } + if (!pileEnd.empty()) { + String id = (String)pileEnd.peek(); + Float f = (Float)hashEnd.get(id); + if (when.floatValue() >= f.floatValue()) { + id = (String)pileEnd.pop(); + fireStopAnnotation(id); + } + } + } +/*-----------------------------------------------------------------------*/ + private void vide_Pile() { + while (!pileEnd.empty()) { //vider la pile des items qui ne sont pas + String id = (String)pileEnd.pop(); //encore fini + if (pileStart.search(id) == -1) { + fireStopAnnotation(id); + } + } + } + private void remplisPileStart(Float start, Float end) { + vide_Pile(); + pileStart.removeAllElements(); + pileEnd.removeAllElements(); + for (int i=orderEndID.size()-1; i!=-1; i--) { + String id = (String)orderEndID.elementAt(i); + Float f = (Float)hashEnd.get(id); + if ((f.floatValue() > start.floatValue()) && (f.floatValue() <= end.floatValue())) { + pileEnd.push(id); + } + } + for (int i=orderStartID.size()-1; i!=-1; i--) { + String id = (String)orderStartID.elementAt(i); + Float f = (Float)hashStart.get(id); + if ((f.floatValue() >= start.floatValue()) && (f.floatValue() < end.floatValue())) { + pileStart.push(id); + } + } + } + private void fireStartAnnotation(String id) + { + //see javadocs on EventListenerList for how following array is structured + Object[] listeners = listenerList.getListenerList(); + + for (int i = listeners.length-2; i>=0; i-=2) + { + if (listeners[i]==AnnotationPlayer.class) + ((AnnotationPlayer)listeners[i+1]).startAnnotation(id); + } + } + private void fireStopAnnotation(String id) + { + //see javadocs on EventListenerList for how following array is structured + Object[] listeners = listenerList.getListenerList(); + + for (int i = listeners.length-2; i>=0; i-=2) + { + if (listeners[i]==AnnotationPlayer.class) + ((AnnotationPlayer)listeners[i+1]).stopAnnotation(id); + } + } +/*-----------------------------------------------------------------------*/ + private String when() { + if (player == null) + return "-1"; + if (player.getState() != Controller.Started) + return "-1"; + long currTime = player.getMediaNanoseconds(); + Float time = new Float(currTime); + float f = (time.floatValue() / 1000000000); + return Float.toString(f); + } + private boolean play(Float from, Float to) { + if (player == null) + return false; + final Time startTime = new Time((long)(from.floatValue() * 1000000000)); + try { + if (player.getState() == Controller.Started) + player.stop(); + while (player.getState() == Controller.Unrealized) + ; +// player.stop(); + if (to == null) { + stopTime = null; + player.setStopTime(Clock.RESET); + } else { + stopTime = new Time((long)(to.floatValue() * 1000000000)); + player.setStopTime(stopTime); + } + player.setMediaTime(startTime); + player.prefetch(); + player.start(); + return true; + } catch(NotRealizedError err) { + System.out.println("NotRealizedError"); + return false; + } + } +/*-----------------------------------------------------------------------*/ + public void openPlayer() { + try { + player = Manager.createPlayer(mediaURL); + player.addControllerListener(this); + } catch (javax.media.NoPlayerException e) { + System.err.println("noplayer exception"); + e.printStackTrace(); + return; + } catch (java.io.IOException ex) { + System.err.println("IO exception"); + ex.printStackTrace(); + return; + } + if (player != null) + player.realize(); + } + public synchronized void controllerUpdate(ControllerEvent event) { + if (player == null) + return; + if (event instanceof RealizeCompleteEvent) { + System.out.println("received RealizeCompleteEvent event"); + if (visualComponent == null) { + if (panel == null) { + setLayout(new GridLayout(1,1)); + vPanel = new JPanel(); + vPanel.setLayout( new BorderLayout() ); + if ((visualComponent = player.getVisualComponent())!= null) + vPanel.add("Center", visualComponent); + else { + isMediaAudio = true; + stillLoadingVideo = false; + } + if (!stillLoadingVideo) + { + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + } + add(vPanel); + } + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + isSized = true; + if (stillLoadingVideo) + player.start(); + } else if (event instanceof StartEvent) { + StartEvent se = (StartEvent)event; + Time t = se.getMediaTime(); + long longt = t.getNanoseconds(); + Float from = new Float(longt); + float f = (from.floatValue() / 1000000000); + from = new Float(f); + t = player.getStopTime(); + longt = t.getNanoseconds(); + to = new Float(longt); + f = (to.floatValue() / 1000000000); + to = new Float(f); + remplisPileStart(from, to); + if (timer != null) + { + timer.cancel(); + timer = null; + } + timer = new java.util.Timer(true); + timer.schedule(new TimerTask() { + public void run() { + //this is specifically for the MPG stop time bug + if (stopTime != null) + if (player.getMediaTime().getNanoseconds() > stopTime.getNanoseconds()) + player.stop(); + cmd_nextEvent(); + }}, 0, 15); + } else if (event instanceof StopEvent) { + pauseTime = player.getMediaTime(); + + /*messy problems require messy solutions: + if the slider is present, dragging it while playing creates + a RestartingEvent, and if I set the media time here it messes up + and barely plays at all (maybe because it cancels the previously + set media time? - I don't know). + + but it seems that if you press the play/pause button on the + control widget, then you need to set the media time upon stop + (probably because of problem noted below, namely that you get + weird results if you do player.start() without setting the media + time.*/ + + if (!(event instanceof RestartingEvent)) + player.setMediaTime(pauseTime); + + stopTime = null; + + System.out.println("received StopEvent"); + + if (timer != null) + { + timer.cancel(); + timer = null; + } + if (stillLoadingVideo) + { + System.out.println("received EndOfMediaEvent"); + stillLoadingVideo = false; + player.stop(); + if ((controlComponent = player.getControlPanelComponent()) != null) { + if (visualComponent == null) //no video + vPanel.setPreferredSize(new Dimension(400,25)); + vPanel.add("South", controlComponent); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } else if ( event instanceof CachingControlEvent) { + CachingControlEvent e = (CachingControlEvent) event; + System.out.println("got CachingControlEvent: " + e); + if (!isMediaAudio) + stillLoadingVideo = true; + } else if (event instanceof ControllerErrorEvent) { + player = null; + System.err.println("*** ControllerErrorEvent *** " + ((ControllerErrorEvent)event).getMessage()); + } else if (event instanceof PrefetchCompleteEvent) { + if (panel != null) { + panel.invalidate(); + } + parent.invalidate(); + parent.validate(); + parent.repaint(); + } + } +}; \ No newline at end of file diff --git a/source/org/thdl/savant/TextHighlightPlayer.java b/source/org/thdl/savant/TextHighlightPlayer.java new file mode 100644 index 0000000..ab8e592 --- /dev/null +++ b/source/org/thdl/savant/TextHighlightPlayer.java @@ -0,0 +1,104 @@ +package org.thdl.savant; + +import java.awt.*; +import java.util.*; +import javax.swing.*; +import javax.swing.text.*; +import java.awt.event.MouseListener; + +public class TextHighlightPlayer extends JPanel implements AnnotationPlayer +{ + protected JTextComponent text; + protected Hashtable hashStart, hashEnd, highlights; + protected Highlighter highlighter; + protected Highlighter.HighlightPainter highlightPainter; + + public TextHighlightPlayer(TranscriptView view, Color highlightcolor) + { + text = view.getTextComponent(); + text.setEditable(false); + MouseListener[] mls = (MouseListener[])(text.getListeners(MouseListener.class)); + for (int i=0; i0 && next.charAt(0)!='-') + segBuffer.append(' '); + segBuffer.append(next); + } + doc.insertString(endPos.getOffset(), segBuffer.toString(), mas0); + } + startBuffer.append(thisStart); + startBuffer.append(','); + thisEnd = String.valueOf(endPos.getOffset()); + endBuffer.append(thisEnd); + endBuffer.append(','); + idBuffer.append("s0,"); + t1Buffer.append(current.getAttributeValue("start")); + t1Buffer.append(','); + t2Buffer.append(current.getAttributeValue("end")); + t2Buffer.append(','); + + while (iter.hasNext()) + { + current = (Element)iter.next(); + + while (current.getName().equals("spkr")) + { + doc.insertString(endPos.getOffset(), "\n\n", mas0); + doc.insertString(endPos.getOffset(), current.getAttributeValue("who"), mas); + + if (iter.hasNext()) + current = (org.jdom.Element)iter.next(); + } + + doc.insertString(endPos.getOffset(), "\n", mas0); + counter++; + thisStart = String.valueOf(endPos.getOffset()); + startBuffer.append(thisStart); + startBuffer.append(','); + if (current.getAttributeValue("gls").equals("PAUSE")) + doc.insertString(endPos.getOffset(), "......", mas0); + else { + String segString = current.getAttributeValue("seg"); + StringBuffer segBuffer = new StringBuffer(); + StringTokenizer segTokenizer = new StringTokenizer(segString); + for (int i=0; segTokenizer.hasMoreTokens(); i++) { + String next = segTokenizer.nextToken(); + if (i>0 && next.charAt(0)!='-') + segBuffer.append(' '); + segBuffer.append(next); + } + doc.insertString(endPos.getOffset(), segBuffer.toString(), mas0); + } + thisEnd = String.valueOf(endPos.getOffset()); + endBuffer.append(thisEnd); + endBuffer.append(','); + thisId = "s"+String.valueOf(counter); + idBuffer.append(thisId); + idBuffer.append(','); + t1Buffer.append(current.getAttributeValue("start")); + t1Buffer.append(','); + t2Buffer.append(current.getAttributeValue("end")); + t2Buffer.append(','); + } + + idBuffer.toString(); + t1Buffer.toString(); + t2Buffer.toString(); + startBuffer.toString(); + endBuffer.toString(); + } + catch (BadLocationException ble) + { + ble.printStackTrace(); + } + } + + public JTextComponent getTextComponent() + { + return text; + } + + public Document getDocument() + { + return xmlDoc; + } + + public String getIDs() + { + return idBuffer.toString(); + } + + public String getT1s() + { + return t1Buffer.toString(); + } + + public String getT2s() + { + return t2Buffer.toString(); + } + + public String getStartOffsets() + { + return startBuffer.toString(); + } + + public String getEndOffsets() + { + return endBuffer.toString(); + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/text/DuffCellRenderer.java b/source/org/thdl/tib/text/DuffCellRenderer.java new file mode 100644 index 0000000..7955a38 --- /dev/null +++ b/source/org/thdl/tib/text/DuffCellRenderer.java @@ -0,0 +1,140 @@ +/* +The contents of this file are subject to the AMP Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the AMP web site +(http://www.tibet.iteso.mx/Guatemala/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is Andres Montano Pellegrini. Portions +created by Andres Montano Pellegrini are Copyright 2001 Andres Montano +Pellegrini. All Rights Reserved. + +Contributor(s): Edward Garrett. +*/ + +package org.thdl.tib.text; + +import java.awt.*; +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import javax.swing.border.*; +import javax.swing.text.*; +import org.thdl.tib.input.DuffPane; +import org.thdl.tib.text.*; +import org.thdl.tib.text.TibetanDocument.DuffData; +import java.io.Serializable; + +/** Used by DictionaryTable to display a Tibetan word or phrase + (in either Roman or Tibetan script) in a single cell. + + @author Andrés Montano Pellegrini + @see DictionaryTable +*/ +public class DuffCellRenderer extends DuffPane implements TableCellRenderer, Serializable +{ + + protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); + + // We need a place to store the color the DuffPane should be returned + // to after its foreground and background colors have been set + // to the selection background color. + // These ivars will be made protected when their names are finalized. + private Color unselectedForeground; + private Color unselectedBackground; + + public DuffCellRenderer() + { + super(); + setOpaque(true); + setBorder(noFocusBorder); + } + + /** + * Overrides JComponent.setForeground to assign + * the unselected-foreground color to the specified color. + * + * @param c set the foreground color to this value + */ + public void setForeground(Color c) { + super.setForeground(c); + unselectedForeground = c; + } + + /** + * Overrides JComponent.setForeground to assign + * the unselected-background color to the specified color. + * + * @param c set the background color to this value + */ + public void setBackground(Color c) { + super.setBackground(c); + unselectedBackground = c; + } + + /** + * Notification from the UIManager that the look and feel + * [L&F] has changed. + * Replaces the current UI object with the latest version from the + * UIManager. + * + * @see JComponent#updateUI + */ + public void updateUI() { + super.updateUI(); + setForeground(null); + setBackground(null); + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) + { + if (isSelected) + { + super.setForeground(table.getSelectionForeground()); + super.setBackground(table.getSelectionBackground()); + } + else + { + super.setForeground((unselectedForeground != null) ? unselectedForeground : table.getForeground()); + super.setBackground((unselectedBackground != null) ? unselectedBackground : table.getBackground()); + } + + if (hasFocus) { + setBorder( UIManager.getBorder("Table.focusCellHighlightBorder") ); + if (table.isCellEditable(row, column)) { + super.setForeground( UIManager.getColor("Table.focusCellForeground") ); + super.setBackground( UIManager.getColor("Table.focusCellBackground") ); + } + } else { + setBorder(noFocusBorder); + } + + setValue(value); + + // ---- begin optimization to avoid painting background ---- + Color back = getBackground(); + boolean colorMatch = (back != null) && ( back.equals(table.getBackground()) ) && table.isOpaque(); + setOpaque(!colorMatch); + // ---- end optimization to aviod painting background ---- + + return this; + } + + public void setValue(Object value) + { + TibetanDocument doc = (TibetanDocument) getDocument(); + try + { + doc.remove(0, doc.getLength()); + } + catch (Exception e) + { + System.out.println(e); + } + doc.insertDuff(0, (DuffData []) value); + } +} \ No newline at end of file