/* GNU General Public License CacheWolf is a software for PocketPC, Win and Linux that enables paperless caching. It supports the sites geocaching.com and opencaching.de Copyright (C) 2006 CacheWolf development team See http://www.cachewolf.de/ for more information. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package CacheWolf; import CacheWolf.controls.DateTimeChooser; import CacheWolf.controls.GuiImageBroker; import CacheWolf.controls.InfoBox; import CacheWolf.controls.MyScrollBarPanel; import CacheWolf.database.Attribute; import CacheWolf.database.Attributes; import CacheWolf.database.CWPoint; import CacheWolf.database.CacheHolder; import CacheWolf.database.CacheHolderDetail; import CacheWolf.database.CacheSize; import CacheWolf.database.CacheTerrDiff; import CacheWolf.database.CacheType; import CacheWolf.database.Log; import CacheWolf.database.Travelbug; import CacheWolf.database.TravelbugJourneyList; import CacheWolf.database.TravelbugList; import CacheWolf.exp.OCLogExport; import CacheWolf.navi.Navigate; import CacheWolf.navi.TransformCoordinates; import CacheWolf.utils.CWWrapper; import CacheWolf.utils.Common; import CacheWolf.utils.MyLocale; import CacheWolf.utils.STRreplace; import ewe.fx.Dimension; import ewe.fx.IImage; import ewe.fx.Point; import ewe.fx.Rect; import ewe.fx.mImage; import ewe.graphics.AniImage; import ewe.graphics.InteractivePanel; import ewe.graphics.MosaicPanel; import ewe.io.File; import ewe.io.IOException; import ewe.sys.Convert; import ewe.sys.Time; import ewe.sys.Vm; import ewe.ui.CellPanel; import ewe.ui.Control; import ewe.ui.ControlConstants; import ewe.ui.ControlEvent; import ewe.ui.DataChangeEvent; import ewe.ui.DateChooser; import ewe.ui.Event; import ewe.ui.Form; import ewe.ui.FormBase; import ewe.ui.Gui; import ewe.ui.HtmlDisplay; import ewe.ui.Menu; import ewe.ui.MenuEvent; import ewe.ui.MenuItem; import ewe.ui.ScrollBarPanel; import ewe.ui.ScrollablePanel; import ewe.ui.mButton; import ewe.ui.mCheckBox; import ewe.ui.mComboBox; import ewe.ui.mInput; import ewe.ui.mLabel; import ewe.ui.mTextPad; import ewe.util.Hashtable; import ewe.util.Iterator; import ewe.util.Vector; import ewe.util.mString; /** * Class to create the panel to show the way point details.<br> * Also allows for creation and editing of way points */ public class DetailsPanel extends CellPanel { private MyChoice btnWaypoint; private mInput inpName; private mInput inpOwner; private MyChoice btnType; private MyChoice btnDiff; private MyChoice btnTerr; private MyChoice btnSize; private MyChoice btnMore; private mButton btnCoordinates; private mButton btnCountryState; private mButton btnHint; private LastLogsPanel lastLogs; private mCheckBox cbIsSolved; private mCheckBox cbIsBlacklisted; private mButton btnFoundDate; private mButton btnHiddenDate; private mComboBox chcStatus; private mTextPad waypointNotes; private AttributesViewer attViewer; private CellPanel logPanel; private mTextPad ownLog; private mButton btnLog; private mButton btnLogToOC; private mButton btnEditLog; // ===== data handles ===== /** waypoint to be displayed. */ private CacheHolder ch; private CacheHolder mainCache; // ===== flags ===== /** details have changed FIXME: make this obsolete */ private boolean dirtyDetails = false; /** cache is blacklisted FIXME: make this obsolete */ private boolean blackStatus = false; /** blacklist status was changed by user FIXME: make this obsolete */ private boolean blackStatusChanged = false; /** FIXME */ private boolean needsTableUpdate = false; /** String to display for invalid or not applicable terrain or difficulty values. */ private String newWaypoint; private byte newDifficulty; private byte newTerrain; private byte newCacheType; private byte newCacheSize; private String newHiddenDate; private String hint; private boolean isBigScreen; private final int BUG = 0; private final int GOTO = 1; private final int NOTES = 2; /** * public constructor for detail panels. should only be called from main tab. */ public DetailsPanel() { super(); int anzPerLine = Math.max(1, Preferences.itself().getScreenWidth() / 257); isBigScreen = anzPerLine > 1; inpName = new mInput(); this.btnWaypoint = new MyChoice("blabla", new String[] { "blabla" }); btnHiddenDate = GuiImageBroker.getButton(MyLocale.getMsg(305, "Hidden on:") + MyLocale.getMsg(31415, "Set hidden date"), "calendar"); btnHiddenDate.setToolTip(MyLocale.getMsg(31415, "Set hidden date")); final String[] tdSelectionList = new String[] { "1.0", "1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "5.0" }; btnDiff = new MyChoice(MyLocale.getMsg(1000, "D"), "star0", tdSelectionList); btnDiff.getBtn().setToolTip(MyLocale.getMsg(31415, "Edit difficulty")); btnTerr = new MyChoice(MyLocale.getMsg(1001, "T"), "star0", tdSelectionList); btnTerr.getBtn().setToolTip(MyLocale.getMsg(31415, "Edit terrain")); btnType = new MyChoice(CacheType.type2Gui(CacheType.CW_TYPE_REFERENCE), CacheType.typeImageNameForId(CacheType.CW_TYPE_TRADITIONAL), CacheType.guiTypeStrings()); btnSize = new MyChoice(CacheType.type2Gui(CacheType.CW_TYPE_REFERENCE), CacheType.typeImageNameForId(CacheType.CW_TYPE_TRADITIONAL), CacheSize.guiSizeStrings()); CellPanel ownerPanel = new CellPanel(); ownerPanel.addNext(new mLabel(MyLocale.getMsg(306, "Owner:")), DONTSTRETCH, DONTFILL | LEFT); inpOwner = new mInput(); ownerPanel.addNext(inpOwner, STRETCH, FILL); btnCoordinates = new mButton(); btnCoordinates.setToolTip(MyLocale.getMsg(31415, "Edit coordinates")); btnCountryState = new mButton(""); btnHint = GuiImageBroker.getButton(MyLocale.getMsg(402, "Hint"), "decode"); if (isBigScreen) lastLogs = new LastLogsPanel((int) (0.75 * Preferences.itself().getScreenWidth()), (int) (0.5 * Preferences.itself().getScreenHeight())); else lastLogs = new LastLogsPanel(Preferences.itself().getScreenWidth(), Preferences.itself().getScreenHeight()); attViewer = new AttributesViewer(); String[] texts = new String[] { MyLocale.getMsg(346, "Show travelbugs"), // MyLocale.getMsg(326, "Set as destination and show Compass View"), // MyLocale.getMsg(351, "Add/Edit notes") // }; String[] icons = new String[] { "bug", "goto", "notes" }; btnMore = new MyChoice(MyLocale.getMsg(632, "More"), "more", texts, icons); CellPanel mainPanel = new CellPanel(); mainPanel.equalWidths = true; Vector panelControls = new Vector(); CellPanel panelTypeWaypoint = new CellPanel(); panelTypeWaypoint.addNext(btnWaypoint.getBtn()); panelTypeWaypoint.addLast(btnType.getBtn()); panelControls.add(panelTypeWaypoint); panelControls.add(btnHiddenDate); panelControls.add(ownerPanel); panelControls.add(btnDiff.getBtn()); panelControls.add(btnTerr.getBtn()); panelControls.add(btnSize.getBtn()); panelControls.add(btnCoordinates); if (this.isBigScreen) { panelControls.add(btnCountryState); } panelControls.add(btnHint); panelControls.add(lastLogs); panelControls.add(btnMore.getBtn()); mainPanel.addLast(inpName); // ist | big icons | small icons | no icons | small icon | big icon // 257 | +text | +text | only text| no text | no text // 240 -> 1 | 1 | 1 | 1 | 1 | 1 // 320 -> 1 | 1 | 1 | 1 | 2 | 1 // 480 -> 1 | 2 | 2 | 2 | 3 | 2 // 514 -> 2 // 640 -> 2 | 3 | 3 | 3 | 4 | 3 // 771 -> 3 // 800 -> 3 | 3 | 4 | 4 | 6 | 4 // 1028 -> 4 // 1280 -> 4 | 4 | 6 | 7 | 9 | 7 // 1285 -> 5 // 1920 -> 7 | 9 | 10 | 11 | 11 | 11 int i = 0; for (Iterator ite = panelControls.iterator(); ite.hasNext();) { Control ctrl = (Control) ite.next(); i++; if ((i % anzPerLine) == 0) { mainPanel.addLast(ctrl); } else { mainPanel.addNext(ctrl); } } mainPanel.addLast(null); if (isBigScreen) { mainPanel.setText(MyLocale.getMsg(1201, "Details")); mainPanel.addLast(attViewer, HSTRETCH, HFILL); } addLast(mainPanel, HSTRETCH, HFILL); CellPanel statusPanel = new CellPanel(); CellPanel solvedPanel = new CellPanel(); solvedPanel.addNext(new mLabel(MyLocale.getMsg(362, "solved") + ": "), DONTSTRETCH, DONTFILL | LEFT); cbIsSolved = new mCheckBox(""); solvedPanel.addNext(cbIsSolved); solvedPanel.addNext(new mLabel(MyLocale.getMsg(363, "Blacklist") + ": "), DONTSTRETCH, DONTFILL | LEFT); cbIsBlacklisted = new mCheckBox(""); solvedPanel.addNext(cbIsBlacklisted); statusPanel.addLast(solvedPanel, HSTRETCH, HFILL); CellPanel foundPanel = new CellPanel(); foundPanel.addNext(new mLabel(MyLocale.getMsg(307, "Status:")), DONTSTRETCH, DONTFILL | LEFT); chcStatus = new mComboBox(CacheHolder.GetGuiLogTypes(), 0); foundPanel.addNext(chcStatus, HSTRETCH, (HFILL | RIGHT)); btnFoundDate = GuiImageBroker.getButton("", "calendar"); btnFoundDate.setToolTip(MyLocale.getMsg(31415, "Set found date / time")); foundPanel.addLast(btnFoundDate, DONTSTRETCH, DONTFILL); statusPanel.addLast(foundPanel, HSTRETCH, HFILL); if (isBigScreen) statusPanel.setText(MyLocale.getMsg(307, "Status:")); addLast(statusPanel, HSTRETCH, HFILL); ownLog = new mTextPad(); if (isBigScreen) { logPanel = new CellPanel(); logPanel.setText(" "); btnLog = GuiImageBroker.getButton(MyLocale.getMsg(1052, "Log online in Browser"), ""); btnLogToOC = GuiImageBroker.getButton(MyLocale.getMsg(1210, "logs to OC"), ""); btnEditLog = GuiImageBroker.getButton(MyLocale.getMsg(1055, "Change log (online)"), ""); logPanel.addNext(btnLog); logPanel.addNext(btnLogToOC); logPanel.addLast(btnEditLog); logPanel.addLast(new MyScrollBarPanel(ownLog), STRETCH, FILL); addLast(logPanel, STRETCH, FILL); waypointNotes = new mTextPad(); // waypointNotes.modify(ControlConstants.NotEditable, 0); MyScrollBarPanel sp = new MyScrollBarPanel(waypointNotes); sp.setText(MyLocale.getMsg(308, "Notes")); addLast(sp, STRETCH, FILL); } else { addLast(attViewer, HSTRETCH, HFILL); } } public void clear() { attViewer.clear(); } public boolean getNeedsTableUpdate() { return needsTableUpdate; } public CacheHolder getCache() { return ch; } public boolean isDirty() { return dirtyDetails || needsTableUpdate; } public boolean hasBlackStatusChanged() { return blackStatusChanged; } public void setDetails(final CacheHolder _ch, boolean isNew) { ch = _ch; needsTableUpdate = isNew; mainCache = ch; if (ch.isAddiWpt() && (ch.mainCache != null)) { mainCache = ch.mainCache; } dirtyDetails = false; GuiImageBroker.setButtonText(btnWaypoint.getBtn(), ch.getCode()); int wptsSize = mainCache.addiWpts.size() + 2; String[] waypointList = new String[wptsSize]; String[] iconList = new String[wptsSize]; waypointList[0] = mainCache.getCode(); iconList[0] = CacheType.typeImageNameForId(mainCache.getType()); int tomark = 0; for (int i = 0; i < mainCache.addiWpts.size(); i++) { CacheHolder tmpCh = (CacheHolder) mainCache.addiWpts.get(i); if (ch == tmpCh) tomark = i + 1; waypointList[i + 1] = tmpCh.getCode() + " " + tmpCh.getName(); iconList[i + 1] = CacheType.typeImageNameForId(tmpCh.getType()); } waypointList[wptsSize - 1] = MyLocale.getMsg(311, "Create Waypoint"); iconList[wptsSize - 1] = "newwpt"; this.btnWaypoint.setSelectionList(waypointList, iconList); this.btnWaypoint.mark(tomark); inpName.setText(ch.getName()); btnCoordinates.setText(ch.getWpt().toString()); newHiddenDate = mainCache.getHidden(); GuiImageBroker.setButtonText(btnHiddenDate, MyLocale.getMsg(305, "Hidden on:") + mainCache.getHidden()); inpOwner.setText(mainCache.getOwner()); this.cbIsSolved.setState(ch.isSolved()); chcStatus.setText(ch.getStatusText()); newCacheType = ch.getType(); GuiImageBroker.setButtonIconAndText(btnType.getBtn(), CacheType.type2Gui(newCacheType), GuiImageBroker.makeImageForButton(btnType.getBtn(), CacheType.type2Gui(newCacheType), CacheType.typeImageNameForId(newCacheType))); this.cbIsBlacklisted.setState(ch.isBlack()); blackStatus = ch.isBlack(); blackStatusChanged = false; this.newWaypoint = ch.getCode(); if (this.newWaypoint.length() == 0) { createWptName(); } if (mainCache.hasBugs()) { btnMore.enable(BUG); } else { btnMore.disable(BUG); } newCacheSize = mainCache.getSize(); String text = CacheSize.cw2ExportString(newCacheSize); String icon = CacheSize.cacheSize2ImageName(newCacheSize); IImage btnSizeNewImage = GuiImageBroker.makeImageForButton(btnSize.getBtn(), text, icon); GuiImageBroker.setButtonIconAndText(btnSize.getBtn(), text, btnSizeNewImage); CacheHolderDetail mainCacheDetails = mainCache.getDetails(); attViewer.showImages(mainCacheDetails.attributes); if (ch.isAddiWpt() || ch.isCustomWpt()) { disable(btnDiff.getBtn()); disable(btnTerr.getBtn()); disable(btnSize.getBtn()); disable(inpOwner); disable(this.btnHiddenDate); disable(this.cbIsBlacklisted); } else { enable(btnDiff.getBtn()); enable(btnTerr.getBtn()); enable(btnSize.getBtn()); enable(inpOwner); enable(this.btnHiddenDate); enable(this.cbIsBlacklisted); } newDifficulty = mainCache.getDifficulty(); String longD = "-.-"; // Custom or invalid newTerrain = mainCache.getTerrain(); String longT = "-.-"; // Custom or invalid if (!ch.isCustomWpt()) { if (CacheTerrDiff.isValidTD(newTerrain)) { longT = CacheTerrDiff.longDT(newTerrain); } else { mainCache.setIncomplete(true); Preferences.itself().log(mainCache.getCode() + " has wrong terrain " + newTerrain); } if (CacheTerrDiff.isValidTD(newDifficulty)) { longD = CacheTerrDiff.longDT(newDifficulty); } else { mainCache.setIncomplete(true); Preferences.itself().log(mainCache.getCode() + " has wrong difficulty " + newDifficulty); } } GuiImageBroker.setButtonIconAndText(btnDiff.getBtn(), MyLocale.getMsg(1000, "D") + " " + longD, GuiImageBroker.makeImageForButton(btnDiff.getBtn(), MyLocale.getMsg(1000, "D") + " " + longD, "star" + newDifficulty)); GuiImageBroker.setButtonIconAndText(btnTerr.getBtn(), MyLocale.getMsg(1001, "T") + " " + longT, GuiImageBroker.makeImageForButton(btnTerr.getBtn(), MyLocale.getMsg(1001, "T") + " " + longT, "star" + newTerrain)); hint = ""; if (ch.isAddiWpt()) { CacheHolderDetail cacheDetails = ch.getDetails(); hint = STRreplace.replace(cacheDetails.LongDescription, "<br>", "\n"); if (hint.length() > 0) { hint = hint + "\n-\n"; } } hint += STRreplace.replace(Common.rot13(mainCacheDetails.Hints), "<br>", "\n"); if (hint.length() > 0) { enable(btnHint); } else { disable(btnHint); } this.btnCountryState.setText(mainCacheDetails.getCountry() + " / " + mainCacheDetails.getState()); lastLogs.images.clear(); Dimension lastLogsDimension = lastLogs.getMySize(null); int lastLogsWidth = lastLogsDimension.width; int lastLogsHeight = lastLogsDimension.height; int anz = Math.min(5, mainCacheDetails.CacheLogs.size()); for (int i = 0; i < anz; i++) { Log log = mainCacheDetails.CacheLogs.getLog(i); if (!(log.getIcon().equals(Log.MAXLOGICON))) { AniImage ai = new AniImage(log.getIcon()); ai.setLocation(i * Math.max(ai.getWidth(), (int) (lastLogsWidth / anz)), (int) ((lastLogsHeight - ai.getHeight()) / 2)); lastLogs.addImage(ai, log); } } lastLogs.refresh(); ownLog.setText(""); if (isBigScreen) { disable(btnEditLog); disable(btnLogToOC); disable(btnLog); //if (ch.isCacheWpt()) { if (mainCache.getDetails().getOwnLog() != null) { logPanel.setText(MyLocale.getMsg(278, "Eigener Log: ") + mainCache.getDetails().getOwnLog().getLogID()); if (mainCache.getDetails().getOwnLog().getLogID().length() == 0) { enable(btnLog); } else { enable(btnEditLog); String ocWpName = mainCache.getIdOC(); if (ocWpName.length() > 0 && ocWpName.charAt(0) < 65) { enable(btnLogToOC); } else { disable(btnLogToOC); } } ownLog.setText(mainCache.getDetails().getOwnLog().getMessageWithoutHTML()); } else { logPanel.setText(" "); enable(btnLog); disable(btnEditLog); disable(btnLogToOC); } waypointNotes.setText(mainCache.getDetails().getCacheNotes()); //} } } /** * if is addi -> returns the respective AddiWpt if is main -> returns the respective MainWpt */ public void createWptName() { final String wpt = this.newWaypoint.toUpperCase(); if (CacheType.isAddiWpt(newCacheType) // && MainTab.itself.mainCache != null // && (MainTab.itself.mainCache.startsWith("GC") // || OC.isOC(MainTab.itself.mainCache) // || MainTab.itself.mainCache.startsWith("CW")) && wpt.startsWith("CW")) { // for creating the Addiname on creating a new Waypoint MainTab.itself.lastselected = MainTab.itself.mainCache; this.newWaypoint = MainForm.profile.getNewAddiWayPointName(MainTab.itself.mainCache); } if (!CacheType.isAddiWpt(newCacheType) && !(wpt.startsWith("GC") || OC.isOC(wpt) || wpt.startsWith("CW"))) { this.newWaypoint = MainForm.profile.getNewWayPointName("CW"); } } /** * Method to react to a user input. */ public void onEvent(final Event ev) { ev.consumed = true; if (ev instanceof DataChangeEvent) { if (ch == null) return; if (ev.target == this.inpName) { if (ch.setName(inpName.getText().trim())) { dirtyDetails = true; } } else if (ev.target == this.inpOwner) { dirtyDetails = true; } else if (ev.target == this.ownLog) { dirtyDetails = true; } else if (ev.target == this.waypointNotes) { dirtyDetails = true; } else { //Preferences.itself().log("DataChangeEvent at Details for " + ev.target.toString() + ". DirtyDetails not set."); dirtyDetails = true; } // FIXME: check if something was actually changed, since datacachnge events also occur if you just hop through the fields with the tab key (Why? don't know!) } else if (ev instanceof MenuEvent) { if (ev.type == MenuEvent.SELECTED) { Menu menu = ((MenuEvent) ev).menu; if (menu == this.btnType.getMnu()) { if (btnType.mark(btnType.getSelectedIndex())) { newCacheType = CacheType.guiSelect2Cw(btnType.getSelectedIndex()); GuiImageBroker.setButtonIconAndText(btnType.getBtn(), CacheType.type2Gui(newCacheType), GuiImageBroker.makeImageForButton(btnType.getBtn(), CacheType.type2Gui(newCacheType), CacheType.typeImageNameForId(newCacheType))); createWptName(); if (CacheType.isCacheWpt(newCacheType)) { enable(btnTerr.getBtn()); enable(btnDiff.getBtn()); enable(btnSize.getBtn()); enable(inpOwner); enable(this.btnHiddenDate); btnMore.enable(BUG); enable(this.cbIsBlacklisted); } else { disable(btnTerr.getBtn()); disable(btnDiff.getBtn()); disable(btnSize.getBtn()); disable(inpOwner); disable(this.btnHiddenDate); btnMore.disable(BUG); disable(this.cbIsBlacklisted); newCacheSize = CacheSize.CW_SIZE_NOTCHOSEN; GuiImageBroker.setButtonIconAndText(btnSize.getBtn(), CacheSize.cw2ExportString(newCacheSize), GuiImageBroker.makeImageForButton(btnSize.getBtn(), CacheSize.cw2ExportString(newCacheSize), CacheSize.cacheSize2ImageName(newCacheSize))); this.newTerrain = CacheTerrDiff.CW_DT_UNSET; this.newDifficulty = CacheTerrDiff.CW_DT_UNSET; GuiImageBroker.setButtonIconAndText(btnDiff.getBtn(), MyLocale.getMsg(1000, "D"), GuiImageBroker.makeImageForButton(btnDiff.getBtn(), MyLocale.getMsg(1000, "D"), "star0")); GuiImageBroker.setButtonIconAndText(btnTerr.getBtn(), MyLocale.getMsg(1001, "T"), GuiImageBroker.makeImageForButton(btnTerr.getBtn(), MyLocale.getMsg(1001, "T"), "star0")); } dirtyDetails = true; } } else if (menu == this.btnWaypoint.getMnu()) { String selectedValue = (String) btnWaypoint.getSelectedValue(); if (selectedValue.startsWith(this.newWaypoint)) { // editieren InfoBox inf = new InfoBox(MyLocale.getMsg(757, "Input"), MyLocale.getMsg(756, "Edit waypoint"), InfoBox.INPUT); inf.setInput(this.newWaypoint); if (inf.execute() == FormBase.IDOK) { this.newWaypoint = inf.getInput().trim().toUpperCase(); if (!this.newWaypoint.equals(this.ch.getCode())) { // perhaps check against internal DB // filename is LowerCase if ((new File(MainForm.profile.dataDir + this.newWaypoint.toLowerCase() + ".xml")).exists()) { new InfoBox("Warning :", this.newWaypoint + "\n" + MyLocale.getMsg(275, "Waypoint already exists!")).wait(FormBase.OKB); // revert waypointname this.newWaypoint = this.ch.getCode(); } else { this.btnWaypoint.setText(this.btnWaypoint.getSelectedIndex(), this.newWaypoint + " " + ch.getName()); this.btnWaypoint.getBtn().setText(this.newWaypoint); dirtyDetails = true; needsTableUpdate = true; } } } } else if (selectedValue.equals(MyLocale.getMsg(311, "Create Waypoint"))) { // new waypoint this.createWaypoint(); } else { // change to if (!mainCache.showAddis()) { mainCache.setShowAddis(true); MainTab.itself.tablePanel.refreshTable(); } MainTab.itself.openPanel(MainTab.DETAILS_CARD, mString.split(selectedValue, ' ')[0], MainTab.DETAILS_CARD); } } else if (menu == this.btnDiff.getMnu()) { if (btnDiff.mark(btnDiff.getSelectedIndex())) { this.newDifficulty = (byte) (this.btnDiff.getSelectedIndex() * 5 + 10); String longD = CacheTerrDiff.longDT(this.newDifficulty); GuiImageBroker.setButtonIconAndText(btnDiff.getBtn(), MyLocale.getMsg(1000, "D") + " " + longD, GuiImageBroker.makeImageForButton(btnDiff.getBtn(), MyLocale.getMsg(1000, "D") + " " + longD, "star" + this.newDifficulty)); dirtyDetails = true; } } else if (menu == this.btnTerr.getMnu()) { if (btnTerr.mark(btnTerr.getSelectedIndex())) { this.newTerrain = (byte) (btnTerr.getSelectedIndex() * 5 + 10); String longT = CacheTerrDiff.longDT(this.newTerrain); GuiImageBroker.setButtonIconAndText(btnTerr.getBtn(), MyLocale.getMsg(1001, "T") + " " + longT, GuiImageBroker.makeImageForButton(btnTerr.getBtn(), MyLocale.getMsg(1001, "T") + " " + longT, "star" + this.newTerrain)); dirtyDetails = true; } } else if (menu == this.btnSize.getMnu()) { if (btnSize.mark(btnSize.getSelectedIndex())) { newCacheSize = CacheSize.guiSizeStrings2CwSize(btnSize.getSelectedValue()); GuiImageBroker.setButtonIconAndText(btnSize.getBtn(), CacheSize.cw2ExportString(newCacheSize), GuiImageBroker.makeImageForButton(btnSize.getBtn(), CacheSize.cw2ExportString(newCacheSize), CacheSize.cacheSize2ImageName(newCacheSize))); dirtyDetails = true; } } else if (menu == this.btnMore.getMnu()) { switch (btnMore.getSelectedIndex()) { case BUG: final TravelbugInCacheScreen ts = new TravelbugInCacheScreen(ch.getDetails().Travelbugs.toHtml(), "Travelbugs"); ts.execute(this.getFrame(), Gui.CENTER_FRAME); break; case NOTES: if (isBigScreen) { ch.getDetails().setCacheNotes(waypointNotes.getText()); } final NotesScreen nsc = new NotesScreen(ch); nsc.execute(this.getFrame(), Gui.CENTER_FRAME); if (isBigScreen) { waypointNotes.setText(ch.getDetails().getCacheNotes()); } break; case GOTO: if (ch.getWpt().isValid()) { Navigate.itself.setDestination(ch); MainTab.itself.select(MainTab.GOTO_CARD); } break; } } } } else if (ev instanceof ControlEvent && ev.type == ControlEvent.PRESSED) { if (ev.target == btnDiff.getBtn()) { int startIndex = this.newDifficulty; startIndex = (startIndex > 0) ? (startIndex - 10) / 5 : 0; btnDiff.mark(startIndex); btnDiff.showMenu(); } else if (ev.target == btnTerr.getBtn()) { int startIndex = this.newTerrain; startIndex = (startIndex > 0) ? (startIndex - 10) / 5 : 0; btnTerr.mark(startIndex); btnTerr.showMenu(); } else if (ev.target == this.btnSize.getBtn()) { int startIndex = CacheSize.cwSizeId2GuiSizeId(newCacheSize); btnSize.mark(startIndex); btnSize.showMenu(); } else if (ev.target == this.btnType.getBtn()) { int startIndex = CacheType.cw2GuiSelect(newCacheType); btnType.mark(startIndex); btnType.showMenu(); } else if (ev.target == this.btnMore.getBtn()) { btnMore.showMenu(); } else if (ev.target == btnWaypoint.getBtn()) { // mark selected cache btnWaypoint.showMenu(); } else if (ev.target == this.cbIsBlacklisted) { if (ch.isBlack()) { ch.setBlack(false); } else { ch.setBlack(true); } blackStatus = ch.isBlack(); ch.setAttributesFromMainCacheToAddiWpts(); dirtyDetails = true; blackStatusChanged = true; } else if (ev.target == btnCoordinates) { CWPoint coords = new CWPoint(btnCoordinates.getText(), TransformCoordinates.DMM); if (Vm.isMobile()) { CoordsPDAInput InScr = new CoordsPDAInput(TransformCoordinates.DMM, true); if (coords.isValid()) InScr.setCoords(coords); else InScr.setCoords(new CWPoint(0, 0)); if (InScr.execute(null, TOP) == FormBase.IDOK) { dirtyDetails = true; coords = InScr.getCoords(); ch.setWpt(coords); btnCoordinates.setText(coords.toString()); // If the current centre is valid, calculate the distance and bearing to it final CWPoint centre = Preferences.itself().curCentrePt; if (centre.isValid()) { ch.calcDistance(centre); // todo perhaps sortTable } } } else { final CoordsInput cs = new CoordsInput(true); cs.setFields(coords, TransformCoordinates.DMM); if (cs.execute() == FormBase.IDOK) { dirtyDetails = true; coords = cs.getCoords(); ch.setWpt(coords); btnCoordinates.setText(coords.toString()); // If the current centre is valid, calculate the distance and bearing to it final CWPoint centre = Preferences.itself().curCentrePt; if (centre.isValid()) { ch.calcDistance(centre); // todo perhaps sortTable } } } } else if (ev.target == btnFoundDate) { int msgNr = CacheType.getLogMsgNr(ch.getType()); // DateChooser.dayFirst=true; final DateTimeChooser dc = new DateTimeChooser(Vm.getLocale()); dc.title = MyLocale.getMsg(328, "Date found"); dc.setPreferredSize(240, 240); String foundDate = chcStatus.getText(); if (foundDate.startsWith(MyLocale.getMsg(msgNr, "Found") + " ")) { foundDate = foundDate.substring(MyLocale.getMsg(msgNr, "Found").length() + 1); } else if (foundDate.endsWith(MyLocale.getMsg(319, "not Found"))) { foundDate = foundDate.substring(0, foundDate.length() - MyLocale.getMsg(319, "not Found").length()); dc.title = MyLocale.getMsg(330, "Date Not Found"); } foundDate = foundDate.trim(); if (foundDate.length() > 0 && foundDate.indexOf('-') > 0) { // Don't try and parse empty date final Time t = new Time(); try { t.parse(foundDate, "y-M-d H:m"); } catch (IllegalArgumentException e) { try { t.parse(foundDate, "y-M-d"); } catch (IllegalArgumentException e1) { Preferences.itself().log("No parsable date given - should not appear (" + foundDate + ")", e1, true); } } dc.reset(t); } // We can create a not found log with date in two ways: // 1) Exiting the date-time dialog by clicking the x if the status is empty (somewhat // non-standard but quick and dirty) // 2) Exiting the date-time dialog by clicking the tick. Then we check whether // the status field was preset with the not-found text. If yes it stays a not found // but the date is prepended // TODO: The functions for extracting the date and the found/not-found text should not be in the GUI int retCode = dc.execute(); if (retCode == ewe.ui.FormBase.IDOK && !chcStatus.getText().endsWith(MyLocale.getMsg(319, "not Found"))) { chcStatus.setText(MyLocale.getMsg(msgNr, "Found") + " " + Convert.toString(dc.year) + "-" + MyLocale.formatLong(dc.month, "00") + "-" + MyLocale.formatLong(dc.day, "00") + " " + dc.time); dirtyDetails = true; } else if (chcStatus.getText().length() == 0 || (retCode == ewe.ui.FormBase.IDOK && chcStatus.getText().endsWith(MyLocale.getMsg(319, "not Found")))) { chcStatus.setText(dc.year + "-" + MyLocale.formatLong(dc.month, "00") + "-" + MyLocale.formatLong(dc.day, "00") + " " + dc.time + " " + MyLocale.getMsg(319, "not Found")); dirtyDetails = true; } } else if (ev.target == btnHiddenDate) { DateChooser.dayFirst = true; final DateChooser dc = new DateChooser(Vm.getLocale()); dc.title = MyLocale.getMsg(329, "Hidden date"); dc.setPreferredSize(240, 240); if (newHiddenDate.length() == 10) try { dc.setDate(new Time(Convert.parseInt(newHiddenDate.substring(8)), Convert.parseInt(newHiddenDate.substring(5, 7)), Convert.parseInt(newHiddenDate.substring(0, 4)))); } catch (NumberFormatException e) { dc.reset(new Time()); } if (dc.execute() == ewe.ui.FormBase.IDOK) { newHiddenDate = Convert.toString(dc.year) + "-" + MyLocale.formatLong(dc.month, "00") + "-" + MyLocale.formatLong(dc.day, "00"); dirtyDetails = true; // profile.hasUnsavedChanges=true; } } else if (ev.target == btnLog) { String url = ""; if (mainCache.isCacheWpt()) { CacheHolderDetail chD = mainCache.getDetails(); String ownLogMessage = STRreplace.replace(ownLog.getText(), "\n", "<br />"); if (chD != null) { if (chD.getOwnLog() != null) { // Cache schon im CW gelogged ownLogMessage = chD.getOwnLog().getMessage(); } } if (ownLogMessage.length() > 0) { Vm.setClipboardText(mainCache.getStatus() + '\n' + "<br>" + ownLogMessage); } if (mainCache.isOC()) { if (chD != null) { url = chD.URL; if (url.indexOf("viewcache") >= 0) { url = STRreplace.replace(url, "viewcache", "log"); } } else { url = "http://" + OC.getOCHostName(mainCache.getCode()) + "/log.php?wp=" + mainCache.getCode(); } } else { // bei GC loggen url = "http://www.geocaching.com/seek/log.aspx?ID=" + mainCache.getCacheID(); } if (url.length() > 0) { callExternalProgram(Preferences.itself().browser, url); } } else { if (mainCache.isCustomWpt() && mainCache.getCode().startsWith("GC")) { url = "http://www.geocaching.com/seek/log.aspx?ID=" + mainCache.getCacheID(); callExternalProgram(Preferences.itself().browser, url); } } } else if (ev.target == btnLogToOC) { // GC und schon gelogged --> log bei OC eintragen OCLogExport.doOneLog(mainCache); MainTab.itself.tablePanel.refreshTable(); } else if (ev.target == btnEditLog) { String url = ""; if (mainCache.isCacheWpt()) { CacheHolderDetail chD = mainCache.getDetails(); if (chD != null) { if (chD.getOwnLog() != null) { if (mainCache.isGC()) { url = "http://www.geocaching.com/seek/log.aspx?LID=" + chD.getOwnLog().getLogID(); callExternalProgram(Preferences.itself().browser, url); } } } } } else if (ev.target == this.btnHint) { new InfoBox(MyLocale.getMsg(402, "Hint"), hint).wait(FormBase.OKB); } } } private void createWaypoint() { final CacheHolder newCache = new CacheHolder(); newCache.setWpt(ch.getWpt()); newCache.setType(CacheType.CW_TYPE_STAGE); newCache.setDifficulty(CacheTerrDiff.CW_DT_UNSET); newCache.setTerrain(CacheTerrDiff.CW_DT_UNSET); newCache.setSize(CacheSize.CW_SIZE_NOTCHOSEN); MainTab.itself.newWaypoint(newCache); } private void callExternalProgram(String program, String parameter) { try { CWWrapper.exec(program, parameter); } catch (IOException ex) { new InfoBox(MyLocale.getMsg(5500, "Error"), MyLocale.getMsg(1034, "Cannot start " + program + "!") + "\n" + ex.toString() + "\n" + MyLocale.getMsg(1035, "Possible reason:") + "\n" + MyLocale.getMsg(1036, "A bug in ewe VM, please be") + "\n" + MyLocale.getMsg(1037, "patient for an update")).wait(FormBase.OKB); } } private void enable(final Control ctrl) { if (ctrl.change(0, ControlConstants.Disabled)) ctrl.repaint(); } private void disable(final Control ctrl) { if (ctrl.change(ControlConstants.Disabled, 0)) ctrl.repaint(); } public void saveDirtyWaypoint() { // we have a mix of setting dirty flag (most values) and directly changing the cache values (notes,...). // that doesn't matter as long as we have no revert. // the dirty flag indicates the global change (which is not necessary for the directly changed values). // so each value will be set by the setter, that checks for a change and sets the flag for writing to disk. // // We have to update two objects: // thisCache (a CacheHolderDetail) which contains the full cache which will be written to the cache.xml file // AND // the CacheHolder object which sits in cacheDB int msgNr = CacheType.getLogMsgNr(ch.getType()); // Strip the found message if the status contains a date if (chcStatus.getText().startsWith(MyLocale.getMsg(msgNr, "Found")) && chcStatus.getText().length() >= MyLocale.getMsg(msgNr, "Found").length() + 11) { ch.setStatus(chcStatus.getText().substring(MyLocale.getMsg(msgNr, "Found").length() + 1)); } else { ch.setStatus(chcStatus.getText()); } if (ch.isSolved() != this.cbIsSolved.getState()) ch.setIsSolved(this.cbIsSolved.getState()); if (chcStatus.getText().startsWith(MyLocale.getMsg(msgNr, "Found")) || (ch.getStatus().length() == 10 || ch.getStatus().length() == 16) && ch.getStatus().charAt(4) == '-') { // Use same heuristic condition as in setDetails(CacheHolder) to determine, if this cache has to considered as found. ch.setFound(true); } else ch.setFound(false); if (!ch.isAddiWpt()) { ch.setOwner(inpOwner.getText().trim()); } // special if (ch.getStatus().equals(MyLocale.getMsg(320, "Owner"))) { ch.setOwned(true); } ch.setBlack(blackStatus); final String oldWaypoint = ch.getCode(); ch.setCode(this.newWaypoint); if (!ch.isAddiWpt()) { ch.setSize(newCacheSize); } // If the waypoint does not have a name, give it one if (ch.getCode().equals("")) { ch.setCode(MainForm.profile.getNewWayPointName("CW")); } // Don't allow single letter names=> Problems in updateBearingDistance // This is a hack but faster than slowing down the loop in // updateBearingDistance if (ch.getCode().length() < 2) ch.setCode(ch.getCode() + " "); ch.setName(inpName.getText().trim()); if (!ch.isAddiWpt()) { ch.setHidden(newHiddenDate.trim()); } final byte oldType = ch.getType(); ch.setType(newCacheType); String ownLogText = STRreplace.replace(ownLog.getText(), "\n", "<br />"); Log oldLog = ch.getDetails().getOwnLog(); if (oldLog == null) { if (ownLogText.length() > 0) { // todo must get date from status // todo must set icon to correct value ch.getDetails().setOwnLog(new Log("", Preferences.itself().gcMemberId, "2.png", "1900-01-01", Preferences.itself().myAlias, ownLogText)); } } else { if (ownLogText.length() > 0) oldLog.setMessage(ownLogText); else { oldLog.setLogID(""); oldLog.setMessage(""); } } if (ch.getName().length() == 0) { ch.setName(ch.getCode()); } ch.checkIncomplete(); /* * The references have to be rebuilt if: * the cachetype changed from addi->normal or from normal->addi * or the old or new cachetype is 'addi' and the waypointname has changed */ if (CacheType.isAddiWpt(newCacheType) != CacheType.isAddiWpt(oldType) // || ((CacheType.isAddiWpt(ch.getType()) || CacheType.isAddiWpt(oldType)) && !ch.getCode().equals(oldWaypoint)) // ) { // If we changed the type to addi, check that a parent exists // FIXME: if cache was renamed we need to rebuild CacheDB.hashDB first MainForm.profile.buildReferences(); } else { // set status also on addi wpts ch.setAttributesFromMainCacheToAddiWpts(); } if (!ch.isAddiWpt()) { ch.setDifficulty(this.newDifficulty); ch.setTerrain(this.newTerrain); } if (isBigScreen) { ch.getDetails().setCacheNotes(waypointNotes.getText()); } dirtyDetails = false; needsTableUpdate = false; ch.getDetails().hasUnsavedChanges = true; if (!oldWaypoint.equals(ch.getCode())) { // Delete old XML - File ch.getDetails().deleteFile(MainForm.profile.dataDir + oldWaypoint + ".xml"); } } private class TravelbugInCacheScreen extends Form { private final DispPanel disp = new DispPanel(); private final mButton btCancel; TravelbugInCacheScreen(String text, String title) { super(); this.setTitle(title); this.setPreferredSize(Preferences.itself().getScreenWidth(), Preferences.itself().getScreenHeight()); disp.setHtml(text); final ScrollBarPanel sbp = new MyScrollBarPanel(disp, ScrollablePanel.NeverShowHorizontalScrollers); this.addLast(sbp); this.addLast(btCancel = new mButton(MyLocale.getMsg(3000, "Close")), DONTSTRETCH, FILL); } public void onEvent(Event ev) { if (ev instanceof ControlEvent && ev.type == ControlEvent.PRESSED) { if (ev.target == btCancel) { this.close(0); } } } // Subclassed HtmlDisplay with Pop-up menu private class DispPanel extends HtmlDisplay { private final MenuItem mnuPickupTB, mnuDropTB; private final MenuItem[] tbMenuItems = new MenuItem[2]; private final Menu mnuPopup; DispPanel() { super(); tbMenuItems[0] = mnuPickupTB = new MenuItem(MyLocale.getMsg(6016, "Pick up Travelbug")); tbMenuItems[1] = mnuDropTB = new MenuItem(MyLocale.getMsg(6017, "Drop Travelbug")); mnuPopup = new Menu(tbMenuItems, ""); } public void penRightReleased(Point p) { setMenu(mnuPopup); doShowMenu(p); // direct call (not through doMenu) is neccesary because it will exclude the whole table } public void penHeld(Point p) { setMenu(mnuPopup); doShowMenu(p); } public void popupMenuEvent(Object selectedItem) { if (selectedItem.equals(mnuPickupTB)) { final Travelbug tb = TravelbugPickup.pickupTravelbug(getCache().getDetails().Travelbugs); TravelbugJourneyList tbjList; if (tb != null) { dirtyDetails = true; // Get the list of my travelbugs tbjList = new TravelbugJourneyList(); tbjList.readTravelbugsFile(); // Add the tb to this list tbjList.addTbPickup(tb, MainForm.profile.name, getCache().getCode()); tbjList.saveTravelbugsFile(); setHtml(getCache().getDetails().Travelbugs.toHtml()); repaint(); getCache().hasBugs(getCache().getDetails().Travelbugs.size() > 0); } } else if (selectedItem.equals(mnuDropTB)) { TravelbugJourneyList tbjList; tbjList = new TravelbugJourneyList(); tbjList.readTravelbugsFile(); TravelbugList tbl = tbjList.getMyTravelbugs(); TravelbugScreen tbs = new TravelbugScreen(tbl, MyLocale.getMsg(6017, "Drop a travelbug"), false); tbs.execute(); if (tbs.selectedItem >= 0) { Travelbug tb = tbl.getTB(tbs.selectedItem); getCache().getDetails().Travelbugs.add(tb); tbjList.addTbDrop(tb, MainForm.profile.name, getCache().getCode()); } tbjList.saveTravelbugsFile(); getCache().hasBugs(getCache().getDetails().Travelbugs.size() > 0); setHtml(getCache().getDetails().Travelbugs.toHtml()); repaint(); dirtyDetails = true; } else { super.popupMenuEvent(selectedItem); } } } } } class MyChoice extends Menu { private mButton btn; private Menu mnu; private MenuItem miList[]; private String[] selectionList; private String[] iconList; private int currentIndex; public MyChoice(String btnText, String[] _selectionList) { btn = new mButton(btnText); setSelectionList(_selectionList, null); } public MyChoice(String btnText, String icon, String[] _selectionList) { btn = GuiImageBroker.getButton(btnText, icon); setSelectionList(_selectionList, null); } public MyChoice(String btnText, String icon, String[] _selectionList, String[] _iconList) { btn = GuiImageBroker.getButton(btnText, icon); setSelectionList(_selectionList, _iconList); } public void setSelectionList(String[] _selectionList, String[] _iconList) { selectionList = _selectionList; iconList = _iconList; miList = new MenuItem[selectionList.length]; this.keepFrame = false; this.items.clear(); for (int i = 0; i < selectionList.length; i++) { if (iconList == null) { this.addItem(miList[i] = new MenuItem(selectionList[i])); } else { if (iconList[i].length() > 0) this.addItem(miList[i] = GuiImageBroker.getMenuItem(selectionList[i], iconList[i])); else this.addItem(miList[i] = new MenuItem(selectionList[i])); } } btn.setMenu(this); currentIndex = -1; btn.modifyAll(ControlConstants.WantHoldDown, 0); mnu = this; } public mButton getBtn() { return btn; } public Menu getMnu() { return mnu; } public boolean mark(int newIndex) { if (newIndex == currentIndex) { return false; } else { if (currentIndex > -1) miList[currentIndex].modifiers &= ~MenuItem.Checked; miList[newIndex].modifiers |= MenuItem.Checked; currentIndex = newIndex; return true; } } public void enable(int index) { this.miList[index].modifiers &= ~MenuItem.Disabled; } public void disable(int index) { this.miList[index].modifiers |= MenuItem.Disabled; } public void setText(int index, String text) { selectionList[index] = text; this.items.clear(); for (int i = 0; i < selectionList.length; i++) { if (i != index) { this.addItem(miList[i]); } else { if (iconList == null) { this.addItem(miList[i] = new MenuItem(selectionList[i])); } else { if (iconList[i].length() > 0) this.addItem(miList[i] = GuiImageBroker.getMenuItem(selectionList[i], iconList[i])); else this.addItem(miList[i] = new MenuItem(selectionList[i])); } } } miList[index].modifiers |= MenuItem.Checked; } public int getSelectedIndex() { return selectedIndex; } public String getSelectedValue() { return selectionList[selectedIndex]; } public void showMenu() { Rect startPos = mnu.getRect(); btn.startDropMenu(new Point(startPos.width, 0)); } } class AttributesViewer extends CellPanel { protected int TILESIZE = Attribute.getImageWidth() + 2; protected final int MAX_ICONS_PER_ROW = Preferences.itself().getScreenWidth() / (TILESIZE + 6); protected final int MAX_ROWS = 1 + Attributes.MAXATTRIBS / MAX_ICONS_PER_ROW; protected InteractivePanel iap; protected mLabel mInfo; public AttributesViewer() { iap = new attInteractivePanel(); mInfo = new mLabel(""); iap.setPreferredSize(10, TILESIZE * MAX_ROWS); addLast(iap, HSTRETCH, HFILL); addLast(mInfo, HSTRETCH, HFILL); setBorder(EDGE_BUMP, 5); } public void showImages(Attributes atts) { iap.images.clear(); for (int i = 0; i < atts.count(); i++) { attAniImage img = new attAniImage(atts.getAttribute(i).getImage()); img.info = atts.getAttribute(i).getMsg(); img.location = new Rect((i % MAX_ICONS_PER_ROW) * TILESIZE, (i / MAX_ICONS_PER_ROW) * TILESIZE, TILESIZE, TILESIZE); iap.addImage(img); } iap.repaint(); } public void clear() { iap.images.clear(); } protected class attInteractivePanel extends InteractivePanel { //Overrides: imageMovedOn(...) in InteractivePanel public boolean imageMovedOn(AniImage which) { if (!((attAniImage) which).info.startsWith("*")) { // If text starts with * we have no explanation yet mInfo.setText(((attAniImage) which).info); mInfo.repaintNow(); } return true; } //Overrides: imageMovedOff(...) in InteractivePanel public boolean imageMovedOff(AniImage which) { mInfo.setText(""); mInfo.repaintNow(); return true; } } protected class attAniImage extends AniImage { public String info; attAniImage(mImage img) { super(img); } } } class LastLogsPanel extends MosaicPanel { Hashtable reference = new Hashtable(5); int breite, hoehe; public LastLogsPanel(int _breite, int _hoehe) { breite = _breite; hoehe = _hoehe; } public void addImage(AniImage im, Log log) { reference.put(im, log); addImage(im); } //Overrides: imagePressed(...) in MosaicPanel public boolean imagePressed(AniImage which, Point pos) { if (which != null) { if (reference.containsKey(which)) { HtmlDisplay log = new HtmlDisplay(); log.startHtml(); log.addHtml(((Log) reference.get(which)).toHtml(), new ewe.sys.Handle()); log.endHtml(); log.scrollTo(0, false); new InfoBox(MyLocale.getMsg(403, "Log"), log, breite, hoehe).wait(FormBase.OKB); } } return true; } }