Vocabulary management from PCB, upload and status images, implemented (PCB side)

parent 3c9d879a
...@@ -52,7 +52,7 @@ public class RestapiWrapper { ...@@ -52,7 +52,7 @@ public class RestapiWrapper {
this.token=token; this.token=token;
} }
public void setToken(String token) { public void setToken(String token) {
Log.i(LOG_TAG, "FERNANDO BORRAR: into settoken" + token);this.token=token; this.token=token;
} }
public String getToken() { public String getToken() {
if (token==null) throw new java.lang.NullPointerException("Token has no value. Use constructor properly or RestapiWrapper.setToken must be invoked previously"); return token; if (token==null) throw new java.lang.NullPointerException("Token has no value. Use constructor properly or RestapiWrapper.setToken must be invoked previously"); return token;
...@@ -74,7 +74,6 @@ public class RestapiWrapper { ...@@ -74,7 +74,6 @@ public class RestapiWrapper {
params = new Hashtable<>(1); params = new Hashtable<>(1);
params.put("token", this.token); params.put("token", this.token);
} }
Log.d(LOG_TAG, "POST params:" + params.toString());
HttpAsyncTaskParams httpAsyncTaskParams=new HttpAsyncTaskParams(); HttpAsyncTaskParams httpAsyncTaskParams=new HttpAsyncTaskParams();
httpAsyncTaskParams.request_method=postOrGet.toUpperCase(); httpAsyncTaskParams.request_method=postOrGet.toUpperCase();
httpAsyncTaskParams.listener=listener; httpAsyncTaskParams.listener=listener;
......
...@@ -22,7 +22,7 @@ import java.util.LinkedList; ...@@ -22,7 +22,7 @@ import java.util.LinkedList;
* @version 1.0 * @version 1.0
* @see Room * @see Room
*/ */
public class Action { public abstract class Action {
protected String type; protected String type;
...@@ -36,7 +36,7 @@ public class Action { ...@@ -36,7 +36,7 @@ public class Action {
} }
public String get_type() { return this.type;} public String get_type() { return this.type;}
public abstract String get_action();
protected JSONObject get_json() { protected JSONObject get_json() {
final String param_id_stu="id_stu"; final String param_id_stu="id_stu";
final String param_id_sup="id_sup"; final String param_id_sup="id_sup";
......
...@@ -30,12 +30,12 @@ public class ActionLog implements iRestapiListener { ...@@ -30,12 +30,12 @@ public class ActionLog implements iRestapiListener {
private static final String LOG_TAG = ActionLog.class.getCanonicalName(); private static final String LOG_TAG = ActionLog.class.getCanonicalName();
/** /**
* Online action. It is send byusing web sockets * Online action. It is send by using web sockets
* @param action * @param action
*/ */
public void log(Action action) { public void log(Action action) {
if (PCBcontext.getRoom().inRoom()) if (PCBcontext.getRoom().inRoom())
PCBcontext.getRoom().emit("/stu/action", action); PCBcontext.getRoom().emit(action.get_action(), action);
else { else {
// If there is no room, the action is stored in local DB // If there is no room, the action is stored in local DB
......
...@@ -22,17 +22,11 @@ import java.util.LinkedList; ...@@ -22,17 +22,11 @@ import java.util.LinkedList;
* @version 1.0 * @version 1.0
* @see Room * @see Room
*/ */
public class PictoAction extends Action { public abstract class PictoAction extends Action {
private Picto picto; private Picto picto;
private float gps_lat; private float gps_lat;
private float gps_lon; private float gps_lon;
//Picto Action types
public static final String ADD="Add";
public static final String DELETE="Delete";
public static final String SELECT="Select";
/** /**
* It creates an action for any user regarding a picto, both online and offline actions. * It creates an action for any user regarding a picto, both online and offline actions.
* *
...@@ -41,6 +35,7 @@ public class PictoAction extends Action { ...@@ -41,6 +35,7 @@ public class PictoAction extends Action {
*/ */
public PictoAction(String type, Picto picto){ public PictoAction(String type, Picto picto){
super(type); super(type);
this.picto=picto; this.picto=picto;
} }
......
...@@ -30,6 +30,9 @@ public class PictosAction extends Action { ...@@ -30,6 +30,9 @@ public class PictosAction extends Action {
//Pictos Action types //Pictos Action types
private static final String SHOW="Show"; private static final String SHOW="Show";
private static final String ACTION="/stu/action";
/** /**
* It creates an action for any user regarding a set of pictos, both online and offline actions. * It creates an action for any user regarding a set of pictos, both online and offline actions.
...@@ -76,4 +79,5 @@ public class PictosAction extends Action { ...@@ -76,4 +79,5 @@ public class PictosAction extends Action {
return subPicto; return subPicto;
} }
} public String get_action() {return ACTION;}
\ No newline at end of file }
...@@ -61,11 +61,11 @@ public class Room { ...@@ -61,11 +61,11 @@ public class Room {
Log.e(this.getClass().getCanonicalName(), e.getClass().getCanonicalName() + e.getMessage() + "--" + e.getLocalizedMessage()); Log.e(this.getClass().getCanonicalName(), e.getClass().getCanonicalName() + e.getMessage() + "--" + e.getLocalizedMessage());
} }
} }
public void emit(String url, final Action action, String token) { public void emit(final Action action, String token) {
final String token_param="token"; final String token_param="token";
Log.d(this.getClass().getName(), "Action: " + action.get_type() + " / Attributes emitted: " + action.get_json().toString()); Log.d(this.getClass().getName(), "Action: " + action.get_type() + " / Attributes emitted: " + action.get_json().toString());
try{ try{
this.socket.emit(url, this.common_data(action.get_type(), action.get_json()).put(token_param, token), new Ack() { this.socket.emit(action.get_action(), this.common_data(action.get_type(), action.get_json()).put(token_param, token), new Ack() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
for (Object arg : args) for (Object arg : args)
...@@ -104,10 +104,9 @@ public class Room { ...@@ -104,10 +104,9 @@ public class Room {
this.socket.registerMessage(msg, listener); this.socket.registerMessage(msg, listener);
} }
void subscribe() { void subscribe() {
final String url="/stu/subscribe";
final String action="subscribe";
try { try {
this.emit(url, new Action(action), PCBcontext.getRestapiWrapper().getToken()); SubscribeAction action = new SubscribeAction();
this.emit(action, PCBcontext.getRestapiWrapper().getToken());
}catch (Exception e) { }catch (Exception e) {
Log.e(this.getClass().getCanonicalName(), e.getMessage()); Log.e(this.getClass().getCanonicalName(), e.getMessage());
} }
......
package com.yottacode.pictogram.action;
import com.yottacode.pictogram.dao.Picto;
/**
* User actions regarding a pictogram that happens when the user is online --> they are sent to the server by websockets (Room class)
* It is required, inter alia, to support session state diagram such
* as is depicted at http://scm.ujaen.es/files/note/1042/Estados_y_acciones.pdf
* and http://scm.ujaen.es/softuno/pictogram/wikis/LUActions
* @author Fernando Martinez Santiago
* @version 1.0
* @see Room
*/
public class SubscribeAction extends Action {
//Picto Action types
public static final String SUBSCRIBE="subscribe";
public static final String ACTION="/stu/subscribe";
public SubscribeAction( ){
super(SUBSCRIBE);
}
public String get_action() {return ACTION;}
}
\ No newline at end of file
package com.yottacode.pictogram.action;
import android.util.Log;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.PCBcontext;
import org.json.JSONException;
import org.json.JSONObject;
/**
* User actions regarding a pictogram that happens when the user is online --> they are sent to the server by websockets (Room class)
* It is required, inter alia, to support session state diagram such
* as is depicted at http://scm.ujaen.es/files/note/1042/Estados_y_acciones.pdf
* and http://scm.ujaen.es/softuno/pictogram/wikis/LUActions
* @author Fernando Martinez Santiago
* @version 1.0
* @see Room
*/
public class TalkAction extends PictoAction {
//Picto Action types
public static final String ADD="Add";
public static final String DELETE="Delete";
public static final String SELECT="Select";
private static final String ACTION="/stu/action";
public TalkAction(String type, Picto picto){
super(type, picto);
}
public String get_action() {return ACTION;}
}
\ No newline at end of file
...@@ -9,61 +9,30 @@ import org.json.JSONException; ...@@ -9,61 +9,30 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
/** /**
* The vocabulary is modified from the PCB by a supervisor for a given student * User actions regarding a pictogram that happens when the user is online --> they are sent to the server by websockets (Room class)
* It is required, inter alia, to support session state diagram such
* as is depicted at http://scm.ujaen.es/files/note/1042/Estados_y_acciones.pdf
* and http://scm.ujaen.es/softuno/pictogram/wikis/LUActions
* @author Fernando Martinez Santiago * @author Fernando Martinez Santiago
* @version 1.0 * @version 1.0
* @see Room * @see Room
*/ */
public class VocabularyAction extends Action { public class VocabularyAction extends PictoAction {
Picto picto;
//Picto Action types //Picto Action types
public static final String ADD="Vocabulay_Add";
public static final String DELETE="Vocabulay_Delete";
public static final String DISABLE="Vocabulay_Disable";
public static final String ENABLE="Vocabulay_Enable";
/** public static final String ADD="add";
* It creates an action for any user regarding a picto, both online and offline actions. public static final String ALTERATTRS="update";
* private static final String ACTION="/stu/vocabulary";
* @param type
* @param picto
*/
public VocabularyAction(String type, Picto picto){
super(type);
this.picto=picto; public VocabularyAction(String type, Picto picto){
} super(type, picto);
@Override
public JSONObject get_json(){
final String param_picto="picto";
try {
return super.get_json().put(param_picto, this.get_json_picto());
}catch(JSONException e) {
Log.e(this.getClass().getCanonicalName(),e.getLocalizedMessage());
return null;
}
}
public JSONObject get_json_picto() throws JSONException {
final String param_id_json="id";
final String param_picto="picto";
final String param_expression="expression";
final String param_expr_lang="lang";
final String param_expr_text="text";
final String param_attrs="attributes";
final String param_picto_id="id";
final String param_picto_uri="uri";
final String param_picto_cat="category";
JSONObject subsubPicto = new JSONObject().put(param_picto_id, picto.get_id())
.put(param_picto_uri, picto.get_url())
.put(param_picto_cat, picto.get_category());
JSONObject attributes = new JSONObject(picto.get_json_attrs());
JSONObject expression = new JSONObject().put(param_expr_lang,PCBcontext.getPcbdb().getCurrentUser().get_lang_stu())
.put(param_expr_text,picto.get_translation());
JSONObject subPicto = new JSONObject().put(param_id_json, 1470)
.put(param_picto, subsubPicto)
.put(param_expression,expression)
.put(param_attrs, attributes);
return subPicto;
} }
public String get_action() {return ACTION;}
} }
\ No newline at end of file
...@@ -321,6 +321,7 @@ public class Picto extends Img { ...@@ -321,6 +321,7 @@ public class Picto extends Img {
try { try {
this.attributes.put(JSON_ATTTRS.STATUS, status); this.attributes.put(JSON_ATTTRS.STATUS, status);
status_modified(true); status_modified(true);
new PictoUploader(this).uploadState();
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
Log.e(this.getClass().getCanonicalName(),e.getMessage()); Log.e(this.getClass().getCanonicalName(),e.getMessage());
...@@ -342,9 +343,8 @@ public class Picto extends Img { ...@@ -342,9 +343,8 @@ public class Picto extends Img {
public void status_modified(boolean modified) { public void status_modified(boolean modified) {
if (modified) if (modified)
try { try {
this.attributes.put(JSON_ATTTRS.PCB_STATUS_MODIFICATION,true); this.attributes.put(JSON_ATTTRS.PCB_STATUS_MODIFICATION, true);
PCBcontext.getActionLog().log(new VocabularyAction(this.is_enabled() ? VocabularyAction.ENABLE : VocabularyAction.DISABLE, this)); PCBcontext.getActionLog().log(new VocabularyAction(VocabularyAction.ALTERATTRS, this));
new PictoUploader(this).uploadState();
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
Log.e(this.getClass().getCanonicalName(), e.getMessage()); Log.e(this.getClass().getCanonicalName(), e.getMessage());
......
...@@ -327,7 +327,6 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -327,7 +327,6 @@ public class Vocabulary implements Iterable<Picto> {
picto = new Picto(id, url, exp, cat, coord_x, coord_y); picto = new Picto(id, url, exp, cat, coord_x, coord_y);
addPicto(picto, ImgDownloader.source.local); addPicto(picto, ImgDownloader.source.local);
PCBcontext.getActionLog().log(new VocabularyAction(VocabularyAction.ADD, picto));
new PictoUploader(picto).upload(); //id<0 iif it is a local id new PictoUploader(picto).upload(); //id<0 iif it is a local id
} catch (Exception e) { } catch (Exception e) {
picto=null; picto=null;
......
package com.yottacode.pictogram.grammar; import android.util.Log; import com.github.nkzawa.emitter.Emitter; import org.json.JSONException;import org.json.JSONObject; import com.yottacode.pictogram.dao.Picto;import com.yottacode.pictogram.action.Room; /** * Websocket Vocabulary Room based on Room * @author Fernando Martinez Santiago * @version 1.0 */public class VocabularyTalk implements Emitter.Listener { private static final String URL ="vocabulary"; private Room room; private Vocabulary vocabulary; iVocabularyListener listeners[]; public VocabularyTalk(Room room, iVocabularyListener listeners[]) { this.room = room; this.room.listen(URL, this); this.listeners=listeners; } private void emit(iVocabularyListener.action action, int picto_cat, int picto_id, JSONObject args) { for (iVocabularyListener listener: this.listeners) listener.change(action, picto_cat, picto_id, args); } @Override public void call(Object... args) { final String param_action="action"; final String param_attributes="attributes"; final String param_picto="picto"; final String param_picto_cat="id_cat"; final String action_update="update"; final String action_add="add"; final String action_delete="delete"; JSONObject msg = (JSONObject) args[0]; try { String action = msg.getString(param_action).toLowerCase(); JSONObject picto= msg.getJSONObject(param_attributes).getJSONObject(param_picto); JSONObject attrs_picto = picto.getJSONObject(param_attributes); int picto_id = picto.getInt(param_picto); int picto_cat = attrs_picto.optInt(param_picto_cat, Picto.NO_CATEGORY); Log.d(this.getClass().getName(), "Received message '" + action + "' to picto " + picto_id + " (cat " + picto_cat + ", attrs: "+attrs_picto); this.emit( action.equals(action_update) ? iVocabularyListener.action.update : action.equals(action_add) ? iVocabularyListener.action.add : iVocabularyListener.action.delete , picto_cat, picto_id, attrs_picto); } catch (JSONException e) { Log.e(this.getClass().getCanonicalName(), e.getClass().getCanonicalName() + "--" + e); } }} package com.yottacode.pictogram.grammar; import android.util.Log; import com.github.nkzawa.emitter.Emitter; import org.json.JSONException;import org.json.JSONObject; import com.yottacode.pictogram.dao.Picto;import com.yottacode.pictogram.action.Room; /** * Websocket Vocabulary Room based on Room * @author Fernando Martinez Santiago * @version 1.0 */public class VocabularyTalk implements Emitter.Listener { private static final String URL ="vocabulary"; private Room room; iVocabularyListener listeners[]; public VocabularyTalk(Room room, iVocabularyListener listeners[]) { this.room = room; this.room.listen(URL, this); this.listeners=listeners; } @Override public void call(Object... args) { final String param_action="action"; final String param_attributes="attributes"; final String param_picto="picto"; final String param_picto_cat="id_cat"; final String action_update="update"; final String action_add="add"; final String action_delete="delete"; JSONObject msg = (JSONObject) args[0]; try { String action = msg.getString(param_action).toLowerCase(); JSONObject picto= msg.getJSONObject(param_attributes).getJSONObject(param_picto); JSONObject attrs_picto = picto.getJSONObject(param_attributes); int picto_id = picto.getInt(param_picto); int picto_cat = attrs_picto.optInt(param_picto_cat, Picto.NO_CATEGORY); Log.d(this.getClass().getName(), "Received message '" + action + "' for picto " + picto_id + " (cat " + picto_cat + ", attrs: "+attrs_picto); for (iVocabularyListener listener: this.listeners) listener.change(action.equals(action_update) ? iVocabularyListener.action.update : action.equals(action_add) ? iVocabularyListener.action.add : iVocabularyListener.action.delete , picto_cat, picto_id, attrs_picto); } catch (JSONException e) { Log.e(this.getClass().getCanonicalName(), e.getClass().getCanonicalName() + "--" + e); } }}
\ No newline at end of file \ No newline at end of file
......
...@@ -41,10 +41,12 @@ import com.yottacode.pictogram.action.Action; ...@@ -41,10 +41,12 @@ import com.yottacode.pictogram.action.Action;
import com.yottacode.pictogram.action.ActionLog; import com.yottacode.pictogram.action.ActionLog;
import com.yottacode.pictogram.action.PictoAction; import com.yottacode.pictogram.action.PictoAction;
import com.yottacode.pictogram.action.PictosAction; import com.yottacode.pictogram.action.PictosAction;
import com.yottacode.pictogram.action.TalkAction;
import com.yottacode.pictogram.dao.Picto; import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.dao.User; import com.yottacode.pictogram.dao.User;
import com.yottacode.pictogram.grammar.Vocabulary; import com.yottacode.pictogram.grammar.Vocabulary;
import com.yottacode.pictogram.grammar.iVocabularyListener; import com.yottacode.pictogram.grammar.iVocabularyListener;
import com.yottacode.pictogram.net.PictoUploader;
import com.yottacode.pictogram.tools.Img; import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext; import com.yottacode.pictogram.tools.PCBcontext;
import com.yottacode.pictogram.net.iImgDownloaderListener; import com.yottacode.pictogram.net.iImgDownloaderListener;
...@@ -272,7 +274,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -272,7 +274,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
actualCategory = p; actualCategory = p;
Toast.makeText(context, "El picto pulsado es una categoría", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "El picto pulsado es una categoría", Toast.LENGTH_SHORT).show();
PCBcontext.getActionLog().log(new PictoAction(PictoAction.SELECT, p)); PCBcontext.getActionLog().log(new TalkAction(TalkAction.SELECT, p));
}else if(tapeAdapter.getCount() < maxInTape){ }else if(tapeAdapter.getCount() < maxInTape){
// If the picto selected is not a category and the tape is not full, it is placed in tape // If the picto selected is not a category and the tape is not full, it is placed in tape
...@@ -288,7 +290,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -288,7 +290,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
rl.setBackgroundColor(Color.parseColor("#BDBDBD")); rl.setBackgroundColor(Color.parseColor("#BDBDBD"));
// Call to static log method // Call to static log method
PCBcontext.getActionLog().log(new PictoAction(PictoAction.ADD, p)); PCBcontext.getActionLog().log(new TalkAction(TalkAction.ADD, p));
// Send websocket notification // Send websocket notification
// when clicking a picto, the activity goes to the main category view // when clicking a picto, the activity goes to the main category view
...@@ -312,15 +314,13 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -312,15 +314,13 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
chooseImage(); chooseImage();
// ... // ...
} }
else if (p.is_enabled()){ else {
// Lo deshabilito p.alter_status();
Log.d(LOG_TAG, "Lo deshabilitaría"); LinkedList <Picto> ll;
// .... if (actualCategory != null) ll = order(vocabulary.next(actualCategory));
} else if (!p.is_enabled()){ else ll = order(vocabulary.startSentence());
// Lo habilito panelAdapter.clear();
Log.d(LOG_TAG, "Lo habilitaría"); panelAdapter.addAll(ll);}
// ....
}
} else{ } else{
ClipData.Item item = new ClipData.Item("" + position); ClipData.Item item = new ClipData.Item("" + position);
...@@ -410,7 +410,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -410,7 +410,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
Picto p = tapeAdapter.getLastItem(); Picto p = tapeAdapter.getLastItem();
// Call to static log method // Call to static log method
PCBcontext.getActionLog().log(new PictoAction(PictoAction.DELETE, p)); PCBcontext.getActionLog().log(new TalkAction(TalkAction.DELETE, p));
// Send websocket action // Send websocket action
tapeAdapter.deleteLastView(); tapeAdapter.deleteLastView();
...@@ -856,7 +856,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -856,7 +856,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
load_pictos(view); load_pictos(view);
// Call to static log method // Call to static log method
PCBcontext.getActionLog().log(new PictoAction(PictoAction.ADD, p)); PCBcontext.getActionLog().log(new TalkAction(TalkAction.ADD, p));
// Send websocket notification // Send websocket notification
/* /*
......
...@@ -8,6 +8,8 @@ import com.koushikdutta.ion.Ion; ...@@ -8,6 +8,8 @@ import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.Response; import com.koushikdutta.ion.Response;
import com.yottacode.net.iRestapiListener; import com.yottacode.net.iRestapiListener;
import com.yottacode.pictogram.R; import com.yottacode.pictogram.R;
import com.yottacode.pictogram.action.PictoAction;
import com.yottacode.pictogram.action.VocabularyAction;
import com.yottacode.pictogram.dao.Picto; import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.Img; import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext; import com.yottacode.pictogram.tools.PCBcontext;
...@@ -40,18 +42,19 @@ public class PictoUploader { ...@@ -40,18 +42,19 @@ public class PictoUploader {
public void uploadState( ){ public void uploadState( ){
Hashtable<String, String> params = new Hashtable<String, String>(1); Hashtable<String, String> params = new Hashtable<String, String>(1);
params.put("attributes", picto.get_json_attrs()); params.put("attributes", picto.get_json_attrs());
params.put("id_stu", Integer.toString(PCBcontext.getPcbdb().getCurrentUser().get_id_stu()));
params.put("id_pic", Integer.toString(this.picto.get_id()));
picto.status_modified(false); picto.status_modified(false);
Log.i(this.getClass().getCanonicalName(), "Uploading " + params.toString());
PCBcontext.getRestapiWrapper().ask(PCBcontext.getPcbdb().getCurrentUser().get_restapi_operation_stu() PCBcontext.getRestapiWrapper().ask(PCBcontext.getPcbdb().getCurrentUser().get_restapi_operation_stu()
+ "/picto/" + "/picto"
+ picto.get_id(), params, "put", new iRestapiListener() { , params, "put", new iRestapiListener() {
@Override @Override
public void preExecute() { public void preExecute() {
} }
@Override @Override
public void result(JSONArray result) { public void result(JSONArray result) {
} }
@Override @Override
...@@ -67,6 +70,7 @@ public class PictoUploader { ...@@ -67,6 +70,7 @@ public class PictoUploader {
} }
} }
); );
PCBcontext.getActionLog().log(new VocabularyAction(VocabularyAction.ALTERATTRS,this.picto));
} }
private int uploadImg( Img img) throws UnsupportedEncodingException { private int uploadImg( Img img) throws UnsupportedEncodingException {
int img_id; int img_id;
...@@ -201,6 +205,7 @@ public class PictoUploader { ...@@ -201,6 +205,7 @@ public class PictoUploader {
if (img_id>0) { if (img_id>0) {
uploadAttributes(img_id); uploadAttributes(img_id);
uploadTranslation(img_id); uploadTranslation(img_id);
PCBcontext.getActionLog().log(new VocabularyAction(VocabularyAction.ADD, this.picto));
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment