@@ -7,7 +7,13 @@ | |||
<tags>View</tags> | |||
</children> | |||
</children> | |||
<mainMenu xmi:id="_wtXeQEs0EeqGDvPDavxXPQ" elementId="org.eclipse.ui.main.menu"/> | |||
<mainMenu xmi:id="_FagzMHBjEeuk7d_98DxC5A" elementId="org.eclipse.ui.main.menu"> | |||
<children xsi:type="menu:Menu" xmi:id="_Lvh0gHBjEeuk7d_98DxC5A" elementId="xyz.veronie.bgg.ui.menu.file" label="File" mnemonics="F"> | |||
<children xsi:type="menu:HandledMenuItem" xmi:id="_2_HOsHBkEeuk7d_98DxC5A" elementId="xyz.veronie.bgg.ui.handledmenuitem.save" label="Save..." iconURI="platform:/plugin/xyz.veronie.bgg.ui/icons/noun_Save_16x16.png" tooltip="Save the currently displayed thing list to the internal storage" command="_lA5t8F9TEeuvNqpgCDWpdQ"/> | |||
<children xsi:type="menu:HandledMenuItem" xmi:id="_T6z-cHBkEeuk7d_98DxC5A" elementId="xyz.veronie.bgg.ui.handledmenuitem.loadlist" label="Load..." iconURI="platform:/plugin/xyz.veronie.bgg.ui/icons/noun_open_16x16.png" tooltip="Load a thing list from the internal storage" command="_qyrHAG3zEeuCP7xCflu8WA"/> | |||
<children xsi:type="menu:HandledMenuItem" xmi:id="_RRC8UHBjEeuk7d_98DxC5A" elementId="xyz.veronie.bgg.ui.handledmenuitem.importresult" label="Import..." iconURI="platform:/plugin/xyz.veronie.bgg.ui/icons/noun_import_16x16.png" tooltip="Import a result.txt file written by bgg1tool int the thing list" mnemonics="" command="_rkauIG7REeutwMlAyj2x8w"/> | |||
</children> | |||
</mainMenu> | |||
<trimBars xmi:id="_I6MLEFv-EeqNgfoocONcgg" elementId="xyz.veronie.bgg.ui.trimbar.bottom" side="Bottom"> | |||
<children xsi:type="menu:ToolControl" xmi:id="_JQ6B8Fv-EeqNgfoocONcgg" elementId="xyz.veronie.bgg.ui.toolcontrol.status" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.StatusBar"/> | |||
</trimBars> | |||
@@ -15,10 +21,15 @@ | |||
<children xsi:type="menu:ToolBar" xmi:id="_AX9yMIucEeqEpr8WQZMuMQ" elementId="xyz.veronie.bgg.ui.toolbar.testbar"/> | |||
</trimBars> | |||
</children> | |||
<handlers xmi:id="_a0tuEGAUEeuNUoCJDLJTzQ" elementId="xyz.veronie.bgg.ui.handler.save" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.HandleSaveGamelist" command="_lA5t8F9TEeuvNqpgCDWpdQ"/> | |||
<handlers xmi:id="_xJXjUG3zEeuCP7xCflu8WA" elementId="xyz.veronie.bgg.ui.handler.load" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.HandleLoadGamelist" command="_qyrHAG3zEeuCP7xCflu8WA"/> | |||
<handlers xmi:id="_a0tuEGAUEeuNUoCJDLJTzQ" elementId="xyz.veronie.bgg.ui.handler.save" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.SaveGamelistHandler" command="_lA5t8F9TEeuvNqpgCDWpdQ"/> | |||
<handlers xmi:id="_xJXjUG3zEeuCP7xCflu8WA" elementId="xyz.veronie.bgg.ui.handler.load" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.LoadGamelistHandler" command="_qyrHAG3zEeuCP7xCflu8WA"/> | |||
<handlers xmi:id="_y97SUG7REeutwMlAyj2x8w" elementId="xyz.veronie.bgg.ui.handler.importResultTxt" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.ImportResultTxtHandler" command="_rkauIG7REeutwMlAyj2x8w"/> | |||
<menuContributions xmi:id="_AitwEHBeEeuk7d_98DxC5A" elementId="xyz.veronie.bgg.ui.menucontribution.gamelists" accessibilityPhrase="Game Lists" positionInParent="0"> | |||
<children xsi:type="menu:HandledMenuItem" xmi:id="_JvwHYHBeEeuk7d_98DxC5A" elementId="importResult" label="Import..." tooltip="Import thing list from bgg1tool result.txt file" command="_rkauIG7REeutwMlAyj2x8w"/> | |||
</menuContributions> | |||
<commands xmi:id="_lA5t8F9TEeuvNqpgCDWpdQ" elementId="xyz.veronie.bgg.ui.command.save" commandName="Save" description="save game list"/> | |||
<commands xmi:id="_qyrHAG3zEeuCP7xCflu8WA" elementId="xyz.veronie.bgg.ui.command.load" commandName="Load" description="load game list"/> | |||
<commands xmi:id="_rkauIG7REeutwMlAyj2x8w" elementId="xyz.veronie.bgg.ui.command.importResultTxt" commandName="ImportResultTxt" description="Import result.txt from bgg1tool"/> | |||
<addons xmi:id="_Lw_ZsUqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/> | |||
<addons xmi:id="_Lw_ZskqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/> | |||
<addons xmi:id="_Lw_Zs0qSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/> | |||
@@ -2,18 +2,6 @@ | |||
<?eclipse version="3.4"?> | |||
<plugin> | |||
<extension | |||
id="anotherproduct" | |||
point="org.eclipse.core.runtime.products"> | |||
<product | |||
name="BggToolAnother" | |||
application="org.eclipse.e4.ui.workbench.swt.E4Application"> | |||
<property | |||
name="appName" | |||
value="BggToolAnother"> | |||
</property> | |||
</product> | |||
</extension> | |||
<extension | |||
id="bggtoolanother" | |||
point="org.eclipse.core.runtime.products"> | |||
@@ -36,6 +36,5 @@ public class LocalDbAdapterService { | |||
public List<String> loadThingListNames() throws SQLException { | |||
return sqliteController.getThingLists(); | |||
} | |||
} |
@@ -173,7 +173,7 @@ public class SqliteController { | |||
PreparedStatement thingStatement = connection | |||
.prepareStatement("INSERT OR REPLACE INTO Thing VALUES (?, ?, ?, ?, ?, ?);"); | |||
PreparedStatement listToThingStatement = connection | |||
.prepareStatement("INSERT INTO ThingListToThing VALUES (?, ?);"); | |||
.prepareStatement("INSERT OR IGNORE INTO ThingListToThing VALUES (?, ?);"); | |||
for (Thing thing : things) { | |||
ThingMetaData metaData = thing.getMetaData(); | |||
@@ -266,4 +266,5 @@ public class SqliteController { | |||
} | |||
} |
@@ -12,6 +12,7 @@ import java.net.URLEncoder; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.Map.Entry; | |||
import java.util.Set; | |||
import javax.inject.Inject; | |||
import javax.xml.parsers.DocumentBuilder; | |||
@@ -61,6 +62,21 @@ public class BggApi { | |||
} | |||
} | |||
/// retrieve a list of things from BGG with the given ids | |||
public ArrayList<Thing> getThings(Set<Integer> ids) { | |||
StringBuilder urlStr = new StringBuilder(); | |||
urlStr.append(BASE_URL + "thing?id="); | |||
String sep = ""; | |||
for (Integer integer : ids) { | |||
urlStr.append(sep + integer.toString()); | |||
if(sep.isEmpty()) { | |||
sep = ","; | |||
} | |||
} | |||
return getThings(urlStr.toString()); | |||
} | |||
public ArrayList<Thing> getThingsForUser(String user) throws IllegalArgumentException { | |||
@@ -204,7 +220,7 @@ public class BggApi { | |||
if (nNode.getNodeType() == Node.ELEMENT_NODE) { | |||
Element eElement = (Element) nNode; | |||
// thing | |||
// thing when fetching by user | |||
if( eElement.hasAttribute("objecttype") | |||
&& eElement.getAttribute("objecttype").equals("thing")) | |||
{ | |||
@@ -216,12 +232,45 @@ public class BggApi { | |||
getValue(eElement, "image"), | |||
getValue(eElement, "thumbnail"), | |||
getValue(eElement, "comment"), | |||
Integer.parseInt(getValue(eElement, "numplays")) | |||
Integer.parseInt(getValue(eElement, "numplays")) | |||
); | |||
Thing thing = new Thing(id, tmd); | |||
Thing thing = new Thing(id, tmd); | |||
things.add(thing); | |||
} | |||
} | |||
// when fetching things by id, type is boardgame | |||
else if(eElement.hasAttribute("type") && | |||
eElement.getAttribute("type").equals("boardgame")) | |||
{ | |||
Integer id = Integer.parseInt(eElement.getAttribute("id")); | |||
if(id != 0) { | |||
String name = ""; | |||
NodeList nameList = eElement.getElementsByTagName("name"); | |||
for(int n = 0; n < nameList.getLength(); n++) { | |||
Node nameNode = nameList.item(n); | |||
if (nNode.getNodeType() == Node.ELEMENT_NODE) { | |||
Element nameElement = (Element) nameNode; | |||
if(nameElement.hasAttribute("type") | |||
&& nameElement.getAttribute("type").equals("primary")) | |||
{ | |||
name = nameElement.getAttribute("value"); | |||
break; | |||
} | |||
} | |||
} | |||
ThingMetaData tmd = new ThingMetaData( | |||
id, | |||
name, | |||
getValue(eElement, "image"), | |||
getValue(eElement, "thumbnail"), | |||
getValue(eElement, "comment"), | |||
null | |||
); | |||
Thing thing = new Thing(id, tmd); | |||
things.add(thing); | |||
} | |||
} | |||
// family has "type" | |||
else if(eElement.hasAttribute("type") | |||
&& eElement.getAttribute("type").equals("boardgamefamily")) | |||
@@ -312,6 +361,7 @@ public class BggApi { | |||
return null; | |||
} | |||
private void checkForErrors(Document doc) throws IllegalArgumentException { | |||
NodeList nList = doc.getElementsByTagName("error"); | |||
if(nList.getLength() > 0) { | |||
@@ -97,6 +97,13 @@ public class ThingProvider { | |||
// TODO: handle unsaved current list | |||
this.things = localDbAdapterService.loadThingList(name); | |||
} | |||
/// store things as a new list | |||
public void importList(List<Thing> importThings, String listName) { | |||
if(importThings != null && !importThings.isEmpty()) { | |||
this.things = importThings; | |||
} | |||
} | |||
public int numberOfThings() { | |||
return things.size(); | |||
@@ -35,8 +35,11 @@ public class LoadGameListDialog extends Dialog { | |||
/** | |||
* Create the dialog. | |||
* @param parentShell | |||
* @param handlerService | |||
* @param commandService | |||
*/ | |||
public LoadGameListDialog(Shell parentShell, List<String> thingLists) { | |||
public LoadGameListDialog(Shell parentShell, List<String> thingLists) | |||
{ | |||
super(parentShell); | |||
this.thingLists = thingLists; | |||
setShellStyle(SWT.BORDER | SWT.RESIZE | SWT.APPLICATION_MODAL); | |||
@@ -44,6 +47,7 @@ public class LoadGameListDialog extends Dialog { | |||
/** | |||
* Create contents of the dialog. | |||
* | |||
* @param parent | |||
*/ | |||
@Override | |||
@@ -112,7 +116,11 @@ public class LoadGameListDialog extends Dialog { | |||
}); | |||
column.pack(); | |||
Composite otherActionsComposite = new Composite(container, SWT.NONE); | |||
otherActionsComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); | |||
otherActionsComposite.setLayout(new GridLayout(1, false)); | |||
return container; | |||
} | |||
@@ -121,8 +129,8 @@ public class LoadGameListDialog extends Dialog { | |||
this.setReturnCode(OK); | |||
this.close(); | |||
} | |||
/** | |||
* Create contents of the button bar. | |||
* @param parent | |||
@@ -146,5 +154,5 @@ public class LoadGameListDialog extends Dialog { | |||
public String getSelectedName() { | |||
return selectedName; | |||
} | |||
} |
@@ -0,0 +1,134 @@ | |||
package xyz.veronie.bgg.ui.handlers; | |||
import java.io.BufferedReader; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.eclipse.core.runtime.Path; | |||
import org.eclipse.e4.core.di.annotations.CanExecute; | |||
import org.eclipse.e4.core.di.annotations.Execute; | |||
import org.eclipse.e4.core.services.events.IEventBroker; | |||
import org.eclipse.swt.SWT; | |||
import org.eclipse.swt.widgets.FileDialog; | |||
import org.eclipse.swt.widgets.MessageBox; | |||
import org.eclipse.swt.widgets.Shell; | |||
import xyz.veronie.bgg.result.BggApi; | |||
import xyz.veronie.bgg.result.Thing; | |||
import xyz.veronie.bgg.result.ThingProvider; | |||
import xyz.veronie.bgg.types.EventConstants; | |||
public class ImportResultTxtHandler { | |||
private Shell shell; | |||
@Execute | |||
public void execute(Shell shell, ThingProvider thingProvider, BggApi bggApi, IEventBroker eventBroker) { | |||
this.shell = shell; | |||
FileDialog dialog = new FileDialog(shell, SWT.OPEN); | |||
dialog.setText("Select a result.txt from bgg1tool"); | |||
String[] exfilters = { "*.txt" }; | |||
dialog.setFilterExtensions(exfilters); | |||
String resultPath = dialog.open(); | |||
if(resultPath != null && !resultPath.isEmpty()) { | |||
Set<Integer> thingIds = parseResultTxtIds(resultPath); | |||
if(thingIds != null && !thingIds.isEmpty()) { | |||
String listName = new Path(resultPath).lastSegment() + " (unsaved)"; | |||
eventBroker.send(EventConstants.TOPIC_STATUS, "Fetching entries from BGG..."); | |||
List<Thing> things = bggApi.getThings(thingIds); | |||
thingProvider.importList(things, listName); | |||
eventBroker.send(EventConstants.TOPIC_RESULT_CHANGED, listName); | |||
eventBroker.send(EventConstants.TOPIC_STATUS, "Fetched " + Integer.toString(things.size()) + " things."); | |||
} | |||
} | |||
} | |||
private Set<Integer> parseResultTxtIds(String resultPath) { | |||
FileReader input = null; | |||
String myLine = null; | |||
int lineNo = 0; // count overall lines | |||
int errNo = 0; // count unparsable lines | |||
int dupNo = 0; // count duplicates | |||
try { | |||
input = new FileReader(resultPath); | |||
BufferedReader bufferedReader = new BufferedReader(input); | |||
Set<Integer> ids = new HashSet<Integer>(); | |||
while ( (myLine = bufferedReader.readLine()) != null) | |||
{ | |||
lineNo++; | |||
String[] tokens = myLine.split(","); | |||
if(tokens.length > 0) { | |||
if(tokens[0].equals("id")) continue; // header line | |||
try { | |||
boolean exists = !ids.add(Integer.parseInt(tokens[0])); | |||
if(exists) { | |||
System.out.println("DEBUG: duplicate id: " + tokens[0]); | |||
dupNo++; | |||
} | |||
} | |||
catch (NumberFormatException e) { | |||
errNo++; | |||
System.out.println("WARN: Could not parse id from line " + Integer.toString(lineNo) | |||
+ ", line starts with '" + tokens[0] + "'"); | |||
} | |||
} | |||
} | |||
bufferedReader.close(); | |||
if(ids != null) { | |||
MessageBox msgBox = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK); | |||
StringBuilder msg = new StringBuilder(); | |||
int thingsNo = lineNo - errNo - dupNo - 1; | |||
msg.append("Parsing successful. Found ").append(Integer.toString(thingsNo)).append(" things."); | |||
if(errNo > 0) { | |||
msg.append("\n\rSkipped ").append(Integer.toString(errNo)).append(" line(s)."); | |||
} | |||
if(dupNo > 0) { | |||
msg.append("\n\r").append(Integer.toString(dupNo)).append(" duplicate ids"); | |||
} | |||
msg.append("\n\r"); | |||
msgBox.setMessage(msg.toString()); | |||
msgBox.open(); | |||
} | |||
System.out.println("TRACE: " + ids); | |||
return ids; | |||
} catch (FileNotFoundException e) { | |||
MessageBox msgBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK); | |||
msgBox.setMessage("Could not open file '" + resultPath + "'."); | |||
msgBox.open(); | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
MessageBox msgBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK); | |||
String msg = "Error while parsing '" + resultPath + "'.\r\n" + | |||
"It must have comma separated lines starting with an integer number.\r\n"; | |||
msgBox.setMessage(msg); | |||
msgBox.open(); | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
@CanExecute | |||
public boolean canExecute() { | |||
return true; | |||
} | |||
} |
@@ -6,6 +6,8 @@ import java.util.List; | |||
import javax.inject.Inject; | |||
import org.eclipse.e4.core.commands.ECommandService; | |||
import org.eclipse.e4.core.commands.EHandlerService; | |||
import org.eclipse.e4.core.di.annotations.CanExecute; | |||
import org.eclipse.e4.core.di.annotations.Execute; | |||
import org.eclipse.e4.core.services.events.IEventBroker; | |||
@@ -18,13 +20,14 @@ import xyz.veronie.bgg.result.ThingProvider; | |||
import xyz.veronie.bgg.types.EventConstants; | |||
import xyz.veronie.bgg.ui.dialogs.LoadGameListDialog; | |||
public class HandleLoadGamelist { | |||
@SuppressWarnings("restriction") | |||
public class LoadGamelistHandler { | |||
@Inject | |||
ThingProvider thingProvider; | |||
@Execute | |||
public void execute(Shell shell, IEventBroker eventBroker) { | |||
public void execute(Shell shell, IEventBroker eventBroker, ECommandService commandService, EHandlerService handlerService) { | |||
try { | |||
List<String> thingLists = thingProvider.getThingListNames(); |
@@ -15,19 +15,18 @@ import xyz.veronie.bgg.result.ThingProvider; | |||
import xyz.veronie.bgg.types.EventConstants; | |||
import xyz.veronie.bgg.ui.dialogs.SaveGameListDialog; | |||
public class HandleSaveGamelist { | |||
public class SaveGamelistHandler { | |||
@Inject | |||
ThingProvider thingProvider; | |||
public HandleSaveGamelist() { | |||
public SaveGamelistHandler() { | |||
} | |||
@Execute | |||
public void execute(Shell shell, IEventBroker eventBroker) { | |||
// TODO: disable save if list is empty | |||
if(thingProvider.numberOfThings() == 0) { | |||
MessageBox msgBox = new MessageBox(shell, SWT.ICON_WARNING | SWT.OK); | |||
msgBox.setMessage("To save an empty game list would be like drawing from an empty deck."); | |||
@@ -35,6 +34,7 @@ public class HandleSaveGamelist { | |||
return; | |||
} | |||
// TODO: handle existing name | |||
SaveGameListDialog saveDialog = new SaveGameListDialog(shell); | |||
saveDialog.open(); | |||
@@ -55,6 +55,7 @@ import xyz.veronie.bgg.ui.helpers.BatLayouts; | |||
// TODO: Display selection details on game | |||
// TODO: cache family/geeklist descriptions | |||
// TODO: allow different screen scalings | |||
// TODO: handle existing name | |||
@SuppressWarnings("restriction") | |||
public class BatMain { | |||