Camtech075

FEditor Text Editor edit

Nov 9th, 2011
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.93 KB | None | 0 0
  1. /*
  2. * FE Editor - GBA Fire Emblem (U) ROM editor
  3. *
  4. * Copyright (C) 2008-2011 Hextator,
  5. * hextator (AIM) [email protected] (MSN)
  6. *
  7. * Major thanks to Zahlman (AIM/MSN: [email protected]) for optimization,
  8. * organization and modularity improvements.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 3
  12. * as published by the Free Software Foundation
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. *
  23. * <Description> This class provides a dialog with a text area and other
  24. * appropriate controls for easy modification of the games' scripts
  25. */
  26.  
  27. /* MODIFIED BY CAMTECH075 OF SERENESFOREST -
  28. *
  29. * Changed refresh method to apply changes automatically.
  30. * Removed lines 120-135 (well, commented them out, at least)
  31. * Added "applyChanges" override method at line 306
  32. */
  33.  
  34. package FEditorAdvance;
  35.  
  36. import java.awt.event.ActionListener;
  37. import java.awt.event.ActionEvent;
  38. import java.io.FileWriter;
  39. import java.io.File;
  40. import java.util.Scanner;
  41. import javax.swing.BorderFactory;
  42. import javax.swing.JCheckBox;
  43. import javax.swing.JLabel;
  44. import javax.swing.JScrollPane;
  45. import javax.swing.JTextArea;
  46. import javax.swing.JTextField;
  47. import javax.swing.JPanel;
  48. //import javax.swing.JButton;
  49. import Controls.TablePanel;
  50. import Controls.Process;
  51. import Controls.ProcessComponent;
  52. import Model.Game;
  53. import Model.TextArray;
  54. import Model.Util;
  55.  
  56. public class TextEditor extends Editor<TextArray> {
  57. private TablePanel<TextArray> tablePanel;
  58.  
  59. private JTextArea inputArea;
  60. private JCheckBox regExChkBox;
  61.  
  62. public TextEditor(View view) {
  63. super(view);
  64.  
  65. inputArea = new JTextArea(8, 16);
  66. inputArea.setLineWrap(true);
  67. inputArea.setWrapStyleWord(true);
  68. JScrollPane inputPane = new JScrollPane(inputArea);
  69. inputPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
  70. // Don't limit the size of this!
  71. add(inputPane);
  72.  
  73. // FIXME: This should use TextArray.maxSize(), but there is
  74. // no instance available yet.
  75. tablePanel = new TablePanel<TextArray>(this, 0x1, 0xFFFF, 0);
  76. tablePanel.setMaximumSize(tablePanel.getPreferredSize());
  77. add(tablePanel);
  78.  
  79. JPanel findPanel = new JPanel();
  80. findPanel.add(new JLabel("Input text to find:"));
  81. final JTextField findField = new JTextField(32);
  82. findPanel.add(findField);
  83. findPanel.setMaximumSize(findPanel.getPreferredSize());
  84. add(findPanel);
  85.  
  86. JPanel replacePanel = new JPanel();
  87. replacePanel.add(new JLabel("Input text to replace:"));
  88. final JTextField replaceField = new JTextField(30);
  89. replacePanel.add(replaceField);
  90. replacePanel.setMaximumSize(replacePanel.getPreferredSize());
  91. add(replacePanel);
  92.  
  93. JPanel panelA = new JPanel();
  94. addButtonToPanel(panelA, "Find", new ActionListener() {
  95. public void actionPerformed(ActionEvent a) {
  96. table.moveTo(1); find(findField.getText(), true);
  97. }
  98. });
  99. addButtonToPanel(panelA, "Find Next", new ActionListener() {
  100. public void actionPerformed(ActionEvent a) {
  101. table.next(); find(findField.getText(), true);
  102. }
  103. });
  104. addButtonToPanel(panelA, "Find Previous", new ActionListener() {
  105. public void actionPerformed(ActionEvent a) {
  106. table.prev(); find(findField.getText(), false);
  107. }
  108. });
  109. addButtonToPanel(panelA, "Replace All", new ActionListener() {
  110. public void actionPerformed(ActionEvent a) {
  111. replaceAll(findField.getText(), replaceField.getText());
  112. }
  113. });
  114. regExChkBox = new JCheckBox("Use Reg Ex?");
  115. regExChkBox.setSelected(false);
  116. panelA.add(regExChkBox);
  117. panelA.setMaximumSize(panelA.getPreferredSize());
  118. add(panelA);
  119.  
  120. JPanel panelB = new JPanel();
  121. /**
  122. *addButtonToPanel(panelB, "Apply", new ActionListener() {
  123. * public void actionPerformed(ActionEvent a) {
  124. * table.setText(inputArea.getText());
  125. * // Refresh the input area in case the text
  126. * // was modified in the process of any
  127. * // last second formatting done prior to insertion
  128. * inputArea.setText(table.getText());
  129. * }
  130. *});
  131. *addButtonToPanel(panelB, "Revert", new ActionListener() {
  132. * public void actionPerformed(ActionEvent a) {
  133. * inputArea.setText(table.getText());
  134. * }
  135. *});
  136. */
  137.  
  138. addButtonToPanel(panelB, "Dump...", new ActionListener() {
  139. public void actionPerformed(ActionEvent a) {
  140. dump();
  141. }
  142. });
  143. addButtonToPanel(panelB, "Insert...", new ActionListener() {
  144. public void actionPerformed(ActionEvent a) {
  145. insert();
  146. }
  147. });
  148. addButtonToPanel(panelB, "Quit", new ActionListener() {
  149. public void actionPerformed(ActionEvent a) {
  150. quit();
  151. }
  152. });
  153. panelB.setMaximumSize(panelB.getPreferredSize());
  154. add(panelB);
  155.  
  156. setMinimumSize(getSize());
  157. }
  158.  
  159. @Override
  160. public void setup(Game game) {
  161. table = game.textArray();
  162. // The TablePanel will call back to refresh().
  163. tablePanel.setTable(table);
  164. }
  165.  
  166. /* Hextator sez: This override is redundant and unsafe
  167. @Override
  168. public void cleanup() {
  169. tablePanel.setTable(null); // so it can be GC'd
  170. }
  171. */
  172.  
  173. @Override
  174. //FIXME: Doesn't work, instead displays "[X]" for everything
  175. public void refresh() {
  176. //Camtech - I'm desperately hoping that this works the way I think it
  177. //does; that is, I'm hoping it reads the 'input index' during the call
  178. //to "getText", rather than for each spinner change.
  179. applyChanges();
  180. inputArea.setText(table.getText());
  181. }
  182.  
  183. private void find(final String toFind, final boolean forward) {
  184. if (toFind.equals("")) {
  185. java.awt.Toolkit.getDefaultToolkit().beep();
  186. return;
  187. }
  188.  
  189. final boolean useRegularExpressions = regExChkBox.isSelected();
  190.  
  191. class Finder extends ProcessComponent {
  192. public String found = null;
  193. public boolean regExError = false;
  194.  
  195. public Finder(int iterations, int weight, String description) {
  196. super(iterations, weight, description);
  197. }
  198.  
  199. protected boolean iterate(int i) {
  200. //System.out.println(Util.verboseReport("find iteration"));
  201. String entry = table.getText();
  202. boolean foundMatch;
  203. if (!useRegularExpressions)
  204. foundMatch = entry.indexOf(toFind) != -1;
  205. else {
  206. try {
  207. String[] temp = entry.split(toFind);
  208. foundMatch =
  209. temp != null
  210. && (
  211. temp.length > 1
  212. || temp.length == 0
  213. )
  214. ;
  215. } catch (Exception e) {
  216. regExError = true;
  217. return true;
  218. }
  219. }
  220. if (entry != null && foundMatch) {
  221. found = entry;
  222. return true;
  223. }
  224.  
  225. if (forward) { table.next(); }
  226. else { table.prev(); }
  227. return false;
  228. }
  229. }
  230.  
  231. final Finder f = new Finder(
  232. table.getCurrentSize(), 1, "Searching for text..."
  233. );
  234.  
  235. view.process(
  236. false, // don't show dialogs
  237. new Process(true, f) { // can cancel
  238. @Override
  239. public void finish() {
  240. if (f.found == null) {
  241. if (!f.regExError)
  242. CommonDialogs.showGenericErrorDialog(
  243. "String not found!"
  244. );
  245. else
  246. CommonDialogs.showGenericErrorDialog(
  247. "It seems your regular expression is invalid."
  248. );
  249. } else {
  250. // Synchronize the spinner with the position that was moved to
  251. // behind the scenes.
  252. tablePanel.setIndex(table.getPosition());
  253. // In turn, the tablePanel will call refresh().
  254. }
  255. }
  256. }
  257. );
  258. }
  259.  
  260. class PositionRestoringProcess extends Process {
  261. private int originalPosition;
  262. public PositionRestoringProcess(ProcessComponent component) {
  263. super(false, component); // can't cancel
  264. originalPosition = tablePanel.getIndex();
  265. }
  266.  
  267. @Override
  268. public void finish() {
  269. // The spinner hasn't changed, but the table position needs to be
  270. // reset, and text should be updated to match.
  271. tablePanel.setIndex(originalPosition);
  272. }
  273. }
  274.  
  275. private void replaceAll(final String toFind, final String replaceWith) {
  276. if (toFind.equals("")) {
  277. java.awt.Toolkit.getDefaultToolkit().beep();
  278. return;
  279. }
  280.  
  281. final boolean useRegularExpressions = regExChkBox.isSelected();
  282.  
  283. view.process(
  284. true, // show dialogs
  285. new PositionRestoringProcess(
  286. new ProcessComponent(
  287. table.getCurrentSize(), 1, "Replacing occurrences of text..."
  288. ) {
  289. protected boolean iterate(int i) {
  290. if (i == 0) { return false; }
  291. table.moveTo(i);
  292. String text = table.getText();
  293. if (text != null) {
  294. if (!useRegularExpressions)
  295. table.setText(text.replace(toFind, replaceWith));
  296. else
  297. table.setText(text.replaceAll(toFind, replaceWith));
  298. }
  299. return false;
  300. }
  301. }
  302. )
  303. );
  304. }
  305.  
  306. @Override
  307. public void applyChanges() { table.setText(inputArea.getText()); }
  308. //Camtech - I'm mostly doing things in the safest way I can think of,
  309. //as I don't understand half of this stuff anyway. And still, I'm sure
  310. //I fucked something up somewhere or other.
  311.  
  312. private void dump() {
  313. final FileWriter scriptToDump;
  314. File selectedFile = CommonDialogs.showSaveFileDialog("script dump");
  315. if (selectedFile == null) { return; }
  316.  
  317. try { scriptToDump = new FileWriter(selectedFile); }
  318. catch (Exception e) {
  319. CommonDialogs.showStreamErrorDialog();
  320. return;
  321. }
  322.  
  323. int size = table.getCurrentSize();
  324. view.process(
  325. true, // show dialogs
  326. new PositionRestoringProcess(
  327. new ProcessComponent(size, 1, "Dumping script...") {
  328. protected boolean iterate(int i) {
  329. if (i == 0) { return false; }
  330. table.moveTo(i);
  331. String text = table.getText();
  332. if (text != null) { // should be impossible for text to be null?
  333. try {
  334. scriptToDump.write(String.format(
  335. "Text of ID 0x%04X\n%s\n\n",
  336. i, table.getText()
  337. ).replaceAll("\\n", Util.newline));
  338. } catch (Exception e) {}
  339. }
  340. return false;
  341. }
  342.  
  343. @Override
  344. protected void cleanup() {
  345. try { scriptToDump.close(); }
  346. catch (Exception e) {}
  347. }
  348. }
  349. )
  350. );
  351. }
  352.  
  353. private void insert() {
  354. final Scanner scriptToInsert;
  355. File fileSelected = CommonDialogs.showOpenFileDialog("script dump");
  356. if (fileSelected == null) { return; }
  357.  
  358. try { scriptToInsert = new Scanner(fileSelected); }
  359. catch (Exception e) {
  360. CommonDialogs.showStreamErrorDialog();
  361. return;
  362. }
  363.  
  364. //int writeIndex;
  365. //String indexLine;
  366.  
  367. view.process(
  368. true, // show dialogs
  369. new PositionRestoringProcess(
  370. // We don't know how many iterations there will be, so we set up
  371. // an indeterminate process step and do the loop manually.
  372. new ProcessComponent(1, 0, "Reading script...") {
  373. protected boolean iterate(int i) {
  374. int index = 1;
  375. while (writeEntry(index++, scriptToInsert)) {}
  376. return false;
  377. }
  378.  
  379. @Override
  380. protected void cleanup() {
  381. try { scriptToInsert.close(); }
  382. catch (Exception e) {}
  383. }
  384. }
  385. )
  386. );
  387. }
  388.  
  389. // Return false when we run out of data.
  390. @SuppressWarnings("empty-statement")
  391. private boolean writeEntry(int index, Scanner source) {
  392. String indexLine = "";
  393. while (indexLine.equals("")) {
  394. if (!source.hasNextLine()) { return false; }
  395. indexLine = source.nextLine();
  396. };
  397.  
  398. try {
  399. index = Util.parseInt(
  400. indexLine.substring(indexLine.lastIndexOf(" "))
  401. ) & 0xFFFF;
  402. } catch (Exception e) { /* Use the default counter value. */ }
  403.  
  404. String outString = "";
  405. String line;
  406. do {
  407. if (!source.hasNextLine()) { return false; }
  408. line = source.nextLine();
  409. outString += line + "\n";
  410. } while (!line.endsWith("[X]"));
  411. outString = outString.trim();
  412. table.moveTo(index);
  413. table.setText(outString);
  414. return true;
  415. }
  416. }
  417.  
  418.  
Advertisement
Add Comment
Please, Sign In to add comment