001: package com.salmonllc.examples.example15;
002:
003: //The Salmon Open Framework for Internet Applications (SOFIA)
004: //Copyright (C) 1999 - 2002, Salmon LLC
005: //
006: //This program is free software; you can redistribute it and/or
007: //modify it under the terms of the GNU General Public License version 2
008: //as published by the Free Software Foundation;
009: //
010: //This program is distributed in the hope that it will be useful,
011: //but WITHOUT ANY WARRANTY; without even the implied warranty of
012: //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: //GNU General Public License for more details.
014: //
015: //You should have received a copy of the GNU General Public License
016: //along with this program; if not, write to the Free Software
017: //Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: //
019: //For more information please visit http://www.salmonllc.com
020:
021: import com.salmonllc.swing.PopupManager;
022: import com.salmonllc.swing.SComponentHelper;
023: import com.salmonllc.personalization.ProxySkinManager;
024: import com.salmonllc.personalization.Skin;
025: import com.salmonllc.personalization.SkinManager;
026: import com.salmonllc.sql.*;
027:
028: import javax.swing.*;
029:
030: import java.awt.*;
031: import java.awt.event.KeyAdapter;
032: import java.awt.event.KeyEvent;
033: import java.awt.event.ActionEvent;
034: import java.net.URL;
035: import java.net.MalformedURLException;
036:
037: /**
038: * The main panel for the app. It's job is to tie the other panels together into a unified user interface. The panel
039: * can be hosted in either an applet or an application depending on how we want to deploy the data entry screen.
040: */
041: public class MainPanel extends JPanel implements Runnable,
042: ModelChangedListener {
043: private DetailPanel _detail;
044: private ButtonPanel _buttons;
045: private DataStoreProxy _ds;
046: private Thread _pingThread;
047: private boolean _keepPinging = false;
048: private boolean _connectedToServer = false;
049: private String _serverURL;
050:
051: //Handle key presses
052: KeyAdapter _kl = new KeyAdapter() {
053: public void keyPressed(KeyEvent e) {
054: PopupManager.getPopupManager().hideWindow();
055: if (e.getKeyCode() == KeyEvent.VK_ENTER)
056: saveData();
057: else if (e.getKeyCode() == KeyEvent.VK_PAGE_UP
058: || e.getKeyCode() == KeyEvent.VK_UP) {
059: SComponentHelper.acceptCurrentValue();
060: _ds.gotoPrior();
061: } else if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN
062: || e.getKeyCode() == KeyEvent.VK_DOWN) {
063: SComponentHelper.acceptCurrentValue();
064: _ds.gotoNext();
065: } else if (!e.isActionKey()) {
066: _buttons.setSaveEnabled(true);
067: }
068: }
069: };
070:
071: //Actions for the buttons
072: private class SearchAction extends AbstractAction {
073: public void actionPerformed(ActionEvent e) {
074: if (_buttons.buttonOK("btn.search"))
075: _buttons.grabFocus();
076: }
077: }
078:
079: private class AddAction extends AbstractAction {
080: public void actionPerformed(ActionEvent e) {
081: if (_buttons.buttonOK("btn.add"))
082: _ds.insertRow();
083: }
084: }
085:
086: private class DeleteAction extends AbstractAction {
087: public void actionPerformed(ActionEvent e) {
088: if (_ds.getRowCount() > 0
089: && _buttons.buttonOK("btn.delete"))
090: _ds.deleteRow();
091: }
092: }
093:
094: private class HelpAction extends AbstractAction {
095: public void actionPerformed(ActionEvent e) {
096: if (_buttons.buttonOK("btn.help"))
097: showHelp();
098: }
099: }
100:
101: /**
102: * Creates a new <code>JPanel</code> with a double buffer
103: * and a flow layout.
104: */
105: public MainPanel(String serverURL, String sessionId, int width) {
106: _serverURL = serverURL;
107:
108: //Now set up the rest of the GUI
109: String DataStoreURL = serverURL
110: + "/DataServer/com.salmonllc.examples.example8.ContactModel";
111: String iconURL = serverURL + "/Jsp/example15/images/";
112: PopupManager.setErrorWindowColors(Color.red, Color.white);
113: try {
114: Icon ic = new ImageIcon(new URL(iconURL + "error.gif"));
115: _ds = new DataStoreProxy(DataStoreURL, sessionId, true);
116: _ds.addModelChangedListener(this );
117:
118: setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
119:
120: //set up the list and detail panels
121: Dimension halfSize = new Dimension((width / 2) - 20, 0);
122: ListPanel list = new ListPanel(_ds, ic, width / 2);
123: list.setPreferredSize(halfSize);
124: DetailPanel detail = new DetailPanel(_ds, ic, this );
125: detail.setEnabled(false);
126: detail.setPreferredSize(halfSize);
127: JSplitPane listDetail = new JSplitPane(
128: JSplitPane.HORIZONTAL_SPLIT, list, detail);
129: listDetail.setAlignmentX(Component.CENTER_ALIGNMENT);
130:
131: //set up the button panel
132: ButtonPanel buttons = new ButtonPanel(_ds, this , iconURL);
133: buttons.setAlignmentX(Component.CENTER_ALIGNMENT);
134:
135: //add everything to the main panel
136: Box main = Box.createVerticalBox();
137: main.add(Box.createVerticalStrut(10));
138: main.add(buttons);
139: main.add(Box.createVerticalStrut(10));
140: main.add(listDetail);
141: add(main);
142:
143: setBackground(buttons.getBackground());
144: _detail = detail;
145: _buttons = buttons;
146: _buttons.grabFocus();
147:
148: _connectedToServer = true;
149:
150: //start a thread that pings the server every few minutes
151: //this will keep the session from expiring as long as the applet/application is running
152: _keepPinging = true;
153: _pingThread = new Thread(this );
154: _pingThread.start();
155:
156: //add keyboard actions for the buttons
157: InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
158: ActionMap am = getActionMap();
159:
160: im.put(KeyStroke.getKeyStroke("F1"), "Help");
161: im.put(KeyStroke.getKeyStroke("F10"), "Search");
162: im.put(KeyStroke.getKeyStroke("alt INSERT"), "Add");
163: im.put(KeyStroke.getKeyStroke("alt DELETE"), "Delete");
164:
165: am.put("Search", new SearchAction());
166: am.put("Add", new AddAction());
167: am.put("Delete", new DeleteAction());
168: am.put("Help", new HelpAction());
169:
170: //Now set the look and feel to the default one for the application
171: SkinManager man = new ProxySkinManager(_serverURL
172: + "/PersonalizationServer", sessionId);
173: Skin sk = new Skin();
174: man.load(null, sk);
175: SComponentHelper.applySkin(sk, this );
176: } catch (DataStoreException e) {
177: e.printStackTrace();
178: if (e.getRootCause() != null)
179: e.getRootCause().printStackTrace();
180: } catch (MalformedURLException e) {
181: e.printStackTrace();
182: }
183: }
184:
185: /**
186: * Saves the data, returns true if the save succeeds
187: */
188: public boolean saveData() {
189: SComponentHelper.acceptCurrentValue();
190: if (!_buttons.buttonOK("btn.save"))
191: return true;
192:
193: try {
194: _ds.update();
195: _buttons.setSaveEnabled(false);
196: return true;
197: } catch (DataStoreException ex) {
198: if (ex.getRow() == -1) {
199: JOptionPane.showMessageDialog(SComponentHelper
200: .getParentFrame(this ), ex.getMessage(),
201: "Error Saving Data", JOptionPane.ERROR_MESSAGE);
202: return false;
203: }
204:
205: _ds.gotoRow(ex.getRow());
206: JComponent comp = (JComponent) _detail.getFields().get(
207: ex.getColumn());
208: if (comp != null) {
209: PopupManager.getPopupManager().showErrorWindow(comp,
210: ex.getMessage());
211: Toolkit.getDefaultToolkit().beep();
212: } else {
213: JOptionPane.showMessageDialog(SComponentHelper
214: .getParentFrame(this ), ex.getMessage(),
215: "Error Saving Data", JOptionPane.ERROR_MESSAGE);
216: }
217:
218: return false;
219: }
220: }
221:
222: /**
223: * A thread that keeps pinging the server every few minutes to keep the session alive
224: */
225: public void run() {
226: while (_keepPinging) {
227: try {
228: Thread.sleep(600000);
229: _ds.ping();
230: } catch (Exception e) {
231: }
232: }
233: }
234:
235: /**
236: * Stops pinging the server when the application or applet is finished executing
237: */
238: public void stopPinging() {
239: _keepPinging = false;
240: }
241:
242: /**
243: * checks to see if we connected properly to the server. Throws up an error message and returns false if not.
244: */
245: public boolean checkServerConnection() {
246: if (!_connectedToServer) {
247: JOptionPane.showMessageDialog(SComponentHelper
248: .getParentFrame(this ),
249: "Error connecting to server:" + _serverURL,
250: "Error connecting to server",
251: JOptionPane.ERROR_MESSAGE);
252: return false;
253: }
254: return true;
255: }
256:
257: /**
258: * Loads the Data from the database
259: */
260: public void loadData(String searchText) {
261: if (!checkDataModified())
262: return;
263:
264: SComponentHelper.setWaitCursor(this );
265: try {
266: String text = searchText;
267: String query = null;
268: if (text != null && text.length() > 0) {
269: query = "";
270: String or = "";
271: for (int i = 0; i < _ds.getColumnCount(); i++) {
272: if (_ds.getColumnDataType(i) == DataStoreProxy.DATATYPE_STRING) {
273: query += or + _ds.getColumnDatabaseName(i)
274: + " like '%" + text + "%'";
275: or = " or ";
276: }
277: }
278: }
279: _ds.retrieve(query);
280: _ds.waitForRetrieve();
281: if (!_ds.gotoFirst())
282: _buttons.grabFocus();
283: _buttons.setSaveEnabled(false);
284: } catch (DataStoreException e1) {
285: e1.printStackTrace();
286: }
287: SComponentHelper.setDefaultCursor(this );
288: }
289:
290: /**
291: * If the data has changed, it throws up a dialog which asks the user if they want to save. Returns true if it is OK to continue the requested operation.
292: */
293: public boolean checkDataModified() {
294: SComponentHelper.acceptCurrentValue();
295: if (!_buttons.buttonOK("btn.save"))
296: return true;
297: boolean mod = false;
298: if (_ds.getDeletedCount() > 0)
299: mod = true;
300: else {
301: for (int i = 0; i < _ds.getRowCount(); i++) {
302: int rowStat = _ds.getRowStatus(i);
303: if (rowStat == DataStoreBuffer.STATUS_MODIFIED
304: || rowStat == DataStoreBuffer.STATUS_NEW_MODIFIED) {
305: mod = true;
306: break;
307: }
308: }
309: }
310:
311: if (mod) {
312: int ret = JOptionPane.showConfirmDialog(SComponentHelper
313: .getParentFrame(this ),
314: "Warning, Data has not been saved. Save Now?");
315: if (ret == JOptionPane.YES_OPTION)
316: return saveData();
317: else if (ret == JOptionPane.NO_OPTION)
318: return true;
319: else
320: return false;
321: } else
322: return true;
323: }
324:
325: /**
326: * Returns the key handler that components in the detail form can register with
327: * @return
328: */
329: public KeyAdapter getKeyHandler() {
330: return _kl;
331: }
332:
333: /**
334: * Handles stuff when the model changes
335: */
336: public void modelChanged(ModelChangedEvent evt) {
337: _buttons.setDeleteEnabled(_ds.getRowCount() > 0);
338:
339: if (evt.getType() != ModelChangedEvent.TYPE_DATA_CHANGED)
340: _detail.grabFocus();
341:
342: if (evt.getType() == ModelChangedEvent.TYPE_DATA_CHANGED
343: || evt.getType() == ModelChangedEvent.TYPE_ROW_INSERTED_OR_DELETED)
344: _buttons.setSaveEnabled(true);
345:
346: _detail.setEnabled(_ds.getRowCount() > 0);
347: }
348:
349: /**
350: * Shows a keyboard help dialog
351: */
352: public void showHelp() {
353: JOptionPane
354: .showMessageDialog(
355: this ,
356: "F1=Help\nF10=Search\nEnter=Save\nAlt+Insert=Add\nAlt+Delete=Delete",
357: "Keyboard Help",
358: JOptionPane.INFORMATION_MESSAGE);
359: }
360:
361: }
|