// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.resource.mus; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Locale; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.infinity.gui.BrowserMenuBar; import org.infinity.gui.ButtonPanel; import org.infinity.gui.ButtonPopupMenu; import org.infinity.gui.InfinityScrollPane; import org.infinity.gui.InfinityTextArea; import org.infinity.gui.WindowBlocker; import org.infinity.resource.Closeable; import org.infinity.resource.Profile; import org.infinity.resource.ResourceFactory; import org.infinity.resource.TextResource; import org.infinity.resource.ViewableContainer; import org.infinity.resource.Writeable; import org.infinity.resource.key.BIFFResourceEntry; import org.infinity.resource.key.ResourceEntry; import org.infinity.search.SongReferenceSearcher; import org.infinity.search.TextResourceSearcher; import org.infinity.util.io.FileManager; import org.infinity.util.io.StreamUtils; public final class MusResource implements Closeable, TextResource, ActionListener, Writeable, ItemListener, DocumentListener { private static int lastIndex = -1; private final ResourceEntry entry; private final String text; private final ButtonPanel buttonPanel = new ButtonPanel(); private JTabbedPane tabbedPane; private JMenuItem ifindall, ifindthis, ifindreference; private JPanel panel; private InfinityTextArea editor; private Viewer viewer; private boolean resourceChanged; public MusResource(ResourceEntry entry) throws Exception { this.entry = entry; ByteBuffer buffer = entry.getResourceBuffer(); text = StreamUtils.readString(buffer, buffer.limit()); resourceChanged = false; } // --------------------- Begin Interface ActionListener --------------------- @Override public void actionPerformed(ActionEvent event) { if (buttonPanel.getControlByType(ButtonPanel.Control.SAVE) == event.getSource()) { if (ResourceFactory.saveResource(this, panel.getTopLevelAncestor())) { setDocumentModified(false); } viewer.loadMusResource(this); } else if (buttonPanel.getControlByType(ButtonPanel.Control.EXPORT_BUTTON) == event.getSource()) { ResourceFactory.exportResource(entry, panel.getTopLevelAncestor()); } } // --------------------- End Interface ActionListener --------------------- // --------------------- Begin Interface Closeable --------------------- @Override public void close() throws Exception { lastIndex = tabbedPane.getSelectedIndex(); if (resourceChanged) { Path output; if (entry instanceof BIFFResourceEntry) { output = FileManager.query(Profile.getRootFolders(), Profile.getOverrideFolderName(), entry.toString()); } else { output = entry.getActualPath(); } String options[] = {"Save changes", "Discard changes", "Cancel"}; int result = JOptionPane.showOptionDialog(panel, "Save changes to " + output + '?', "Resource changed", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); if (result == 0) { ResourceFactory.saveResource(this, panel.getTopLevelAncestor()); } else if (result != 1) { throw new Exception("Save aborted"); } } if (viewer != null) { viewer.close(); } } // --------------------- End Interface Closeable --------------------- // --------------------- Begin Interface DocumentListener --------------------- @Override public void insertUpdate(DocumentEvent event) { setDocumentModified(true); } @Override public void removeUpdate(DocumentEvent event) { setDocumentModified(true); } @Override public void changedUpdate(DocumentEvent event) { setDocumentModified(true); } // --------------------- End Interface DocumentListener --------------------- // --------------------- Begin Interface ItemListener --------------------- @Override public void itemStateChanged(ItemEvent event) { if (buttonPanel.getControlByType(ButtonPanel.Control.FIND_MENU) == event.getSource()) { ButtonPopupMenu bpmFind = (ButtonPopupMenu)event.getSource(); if (bpmFind.getSelectedItem() == ifindall) { String type = entry.toString().substring(entry.toString().indexOf(".") + 1); List<ResourceEntry> files = ResourceFactory.getResources(type); new TextResourceSearcher(files, panel.getTopLevelAncestor()); } else if (bpmFind.getSelectedItem() == ifindthis) { List<ResourceEntry> files = new ArrayList<ResourceEntry>(); files.add(entry); new TextResourceSearcher(files, panel.getTopLevelAncestor()); } else if (bpmFind.getSelectedItem() == ifindreference) { new SongReferenceSearcher(entry, panel.getTopLevelAncestor()); } } } // --------------------- End Interface ItemListener --------------------- // --------------------- Begin Interface Resource --------------------- @Override public ResourceEntry getResourceEntry() { return entry; } // --------------------- End Interface Resource --------------------- // --------------------- Begin Interface TextResource --------------------- @Override public String getText() { if (editor == null) return text; else return editor.getText(); } @Override public void highlightText(int linenr, String text) { String s = editor.getText(); int startpos = 0; int i = (s.charAt(0) == '\n') ? 2 : 1; for (; i < linenr; i++) { startpos = s.indexOf("\n", startpos + 1); } if (startpos == -1) return; if (text != null) { // try to select specified text string int wordpos = s.toUpperCase(Locale.ENGLISH).indexOf(text.toUpperCase(Locale.ENGLISH), startpos); if (wordpos != -1) { editor.select(wordpos, wordpos + text.length()); } else { editor.select(startpos, s.indexOf("\n", startpos + 1)); } } else { // select whole line int endpos = s.indexOf("\n", startpos + 1); if (endpos < 0) { endpos = s.length(); } editor.select(startpos, endpos); } editor.getCaret().setSelectionVisible(true); } // --------------------- End Interface TextResource --------------------- // --------------------- Begin Interface Viewable --------------------- @Override public JComponent makeViewer(ViewableContainer container) { panel = new JPanel(new BorderLayout()); try { WindowBlocker.blockWindow(true); viewer = new Viewer(this); tabbedPane = new JTabbedPane(); tabbedPane.addTab("View", viewer); tabbedPane.addTab("Edit", getEditor(container.getStatusBar())); panel.add(tabbedPane, BorderLayout.CENTER); if (lastIndex != -1) { tabbedPane.setSelectedIndex(lastIndex); } else if (BrowserMenuBar.getInstance().getDefaultStructView() == BrowserMenuBar.DEFAULT_EDIT) { tabbedPane.setSelectedIndex(1); } WindowBlocker.blockWindow(false); } catch (Exception e) { WindowBlocker.blockWindow(false); } return panel; } // --------------------- End Interface Viewable --------------------- // --------------------- Begin Interface Writeable --------------------- @Override public void write(OutputStream os) throws IOException { if (editor == null) { StreamUtils.writeString(os, text, text.length()); } else { StreamUtils.writeString(os, editor.getText(), editor.getText().length()); } } // --------------------- End Interface Writeable --------------------- public Viewer getViewer() { return viewer; } private JComponent getEditor(CaretListener caretListener) { ifindall = new JMenuItem("in all " + entry.toString().substring(entry.toString().indexOf(".") + 1) + " files"); ifindthis = new JMenuItem("in this file only"); ifindreference = new JMenuItem("references to this file"); ButtonPopupMenu bpmFind = (ButtonPopupMenu)buttonPanel.addControl(ButtonPanel.Control.FIND_MENU); bpmFind.setMenuItems(new JMenuItem[]{ifindall, ifindthis, ifindreference}); bpmFind.addItemListener(this); editor = new InfinityTextArea(text, true); editor.discardAllEdits(); editor.addCaretListener(caretListener); editor.setFont(BrowserMenuBar.getInstance().getScriptFont()); editor.setMargin(new Insets(3, 3, 3, 3)); editor.setCaretPosition(0); editor.setLineWrap(false); editor.getDocument().addDocumentListener(this); ((JButton)buttonPanel.addControl(ButtonPanel.Control.EXPORT_BUTTON)).addActionListener(this); JButton bSave = (JButton)buttonPanel.addControl(ButtonPanel.Control.SAVE); bSave.addActionListener(this); bSave.setEnabled(getDocumentModified()); JPanel lowerpanel = new JPanel(); lowerpanel.setLayout(new FlowLayout(FlowLayout.CENTER)); lowerpanel.add(buttonPanel); JPanel panel2 = new JPanel(); panel2.setLayout(new BorderLayout()); panel2.add(new InfinityScrollPane(editor, true), BorderLayout.CENTER); panel2.add(lowerpanel, BorderLayout.SOUTH); return panel2; } private boolean getDocumentModified() { return resourceChanged; } private void setDocumentModified(boolean b) { if (b != resourceChanged) { resourceChanged = b; buttonPanel.getControlByType(ButtonPanel.Control.SAVE).setEnabled(resourceChanged); } } }