1 /* 2 * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game 3 * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com> 4 * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21 package org.hedgewars.hedgeroid; 22 23 import java.io.File; 24 import java.io.FileNotFoundException; 25 import java.io.IOException; 26 import java.util.ArrayList; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.NoSuchElementException; 30 31 import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils; 32 import org.hedgewars.hedgeroid.Datastructures.Hog; 33 import org.hedgewars.hedgeroid.Datastructures.Team; 34 import org.hedgewars.hedgeroid.util.FileUtils; 35 36 import android.app.Activity; 37 import android.graphics.Bitmap; 38 import android.graphics.drawable.Drawable; 39 import android.media.MediaPlayer; 40 import android.os.Bundle; 41 import android.util.Log; 42 import android.view.View; 43 import android.view.View.OnClickListener; 44 import android.widget.AdapterView; 45 import android.widget.AdapterView.OnItemSelectedListener; 46 import android.widget.ArrayAdapter; 47 import android.widget.EditText; 48 import android.widget.ImageButton; 49 import android.widget.ImageView; 50 import android.widget.LinearLayout; 51 import android.widget.RelativeLayout; 52 import android.widget.ScrollView; 53 import android.widget.SimpleAdapter; 54 import android.widget.Spinner; 55 import android.widget.SpinnerAdapter; 56 import android.widget.TextView; 57 import android.widget.Toast; 58 59 /** 60 * Edit or create a team. If a team should be edited, it is supplied in the extras 61 * as parameter oldTeamName. 62 */ 63 public class TeamCreatorActivity extends Activity implements Runnable { 64 public static final String PARAMETER_EXISTING_TEAMNAME = "existingTeamName"; 65 private static final String TAG = TeamCreatorActivity.class.getSimpleName(); 66 67 private TextView name; 68 private Spinner difficulty, grave, flag, voice, fort; 69 private ImageView imgFort; 70 private ArrayList<ImageButton> hogDice = new ArrayList<ImageButton>(); 71 private ArrayList<Spinner> hogHat = new ArrayList<Spinner>(); 72 private ArrayList<EditText> hogName = new ArrayList<EditText>(); 73 private ImageButton voiceButton; 74 private ScrollView scroller; 75 private MediaPlayer mp = null; 76 private boolean initComplete = false; 77 78 private String existingTeamName = null; 79 80 private final List<Map<String, ?>> flagsData = new ArrayList<Map<String, ?>>(); 81 private final List<Map<String, ?>> typesData = new ArrayList<Map<String, ?>>(); 82 private final List<Map<String, ?>> gravesData = new ArrayList<Map<String, ?>>(); 83 private final List<Map<String, ?>> hatsData = new ArrayList<Map<String, ?>>(); 84 private final List<String> voicesData = new ArrayList<String>(); 85 private final List<String> fortsData = new ArrayList<String>(); 86 onCreate(Bundle savedInstanceState)87 public void onCreate(Bundle savedInstanceState) { 88 super.onCreate(savedInstanceState); 89 initComplete = false; 90 91 // Restore state and read parameters 92 if(savedInstanceState != null) { 93 existingTeamName = savedInstanceState.getString(PARAMETER_EXISTING_TEAMNAME); 94 } else { 95 existingTeamName = getIntent().getStringExtra(PARAMETER_EXISTING_TEAMNAME); 96 } 97 98 // Set up view 99 setContentView(R.layout.team_creation); 100 101 name = (TextView) findViewById(R.id.txtName); 102 difficulty = (Spinner) findViewById(R.id.spinType); 103 grave = (Spinner) findViewById(R.id.spinGrave); 104 flag = (Spinner) findViewById(R.id.spinFlag); 105 voice = (Spinner) findViewById(R.id.spinVoice); 106 fort = (Spinner) findViewById(R.id.spinFort); 107 108 imgFort = (ImageView) findViewById(R.id.imgFort); 109 110 voiceButton = (ImageButton) findViewById(R.id.btnPlay); 111 112 scroller = (ScrollView) findViewById(R.id.scroller); 113 114 // Wire view elements 115 LinearLayout ll = (LinearLayout) findViewById(R.id.HogsContainer); 116 for (int i = 0; i < ll.getChildCount(); i++) { 117 RelativeLayout team_creation_entry = (RelativeLayout) ll.getChildAt(i); 118 119 hogHat.add((Spinner) team_creation_entry 120 .findViewById(R.id.spinTeam1)); 121 hogDice.add((ImageButton) team_creation_entry 122 .findViewById(R.id.btnTeam1)); 123 hogName.add((EditText) team_creation_entry 124 .findViewById(R.id.txtTeam1)); 125 } 126 127 grave.setAdapter(createMapSpinnerAdapter(gravesData)); 128 flag.setAdapter(createMapSpinnerAdapter(flagsData)); 129 difficulty.setAdapter(createMapSpinnerAdapter(typesData)); 130 SpinnerAdapter hatAdapter = createMapSpinnerAdapter(hatsData); 131 for (Spinner spin : hogHat) { 132 spin.setAdapter(hatAdapter); 133 } 134 135 136 voice.setAdapter(createListSpinnerAdapter(voicesData)); 137 voiceButton.setOnClickListener(voiceClicker); 138 139 fort.setAdapter(createListSpinnerAdapter(fortsData)); 140 fort.setOnItemSelectedListener(fortSelector); 141 142 new Thread(this).start(); 143 } 144 createMapSpinnerAdapter(List<? extends Map<String, ?>> data)145 private SpinnerAdapter createMapSpinnerAdapter(List<? extends Map<String, ?>> data) { 146 SimpleAdapter sa = new SimpleAdapter(this, data, 147 R.layout.spinner_textimg_entry, new String[] { "txt", "img" }, 148 new int[] { R.id.spinner_txt, R.id.spinner_img }); 149 sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry); 150 sa.setViewBinder(viewBinder); 151 return sa; 152 } 153 createListSpinnerAdapter(List<String> data)154 private SpinnerAdapter createListSpinnerAdapter(List<String> data) { 155 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, data); 156 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 157 return adapter; 158 } 159 run()160 public void run(){ 161 try { 162 final List<Map<String, ?>> gravesDataNew = FrontendDataUtils.getGraves(this); 163 runOnUiThread(new Runnable(){ 164 public void run() { 165 gravesData.addAll(gravesDataNew); 166 ((SimpleAdapter)grave.getAdapter()).notifyDataSetChanged(); 167 } 168 }); 169 170 final List<Map<String, ?>> flagsDataNew = FrontendDataUtils.getFlags(this); 171 runOnUiThread(new Runnable(){ 172 public void run() { 173 flagsData.addAll(flagsDataNew); 174 ((SimpleAdapter)flag.getAdapter()).notifyDataSetChanged(); 175 } 176 }); 177 178 final List<Map<String, ?>> typesDataNew = FrontendDataUtils.getTypes(this); 179 runOnUiThread(new Runnable(){ 180 public void run() { 181 typesData.addAll(typesDataNew); 182 ((SimpleAdapter)difficulty.getAdapter()).notifyDataSetChanged(); 183 } 184 }); 185 186 final List<Map<String, ?>> hatsDataNew = FrontendDataUtils.getHats(this); 187 runOnUiThread(new Runnable(){ 188 public void run() { 189 hatsData.addAll(hatsDataNew); 190 ((SimpleAdapter)hogHat.get(0).getAdapter()).notifyDataSetChanged(); 191 } 192 }); 193 194 final List<String> voicesDataNew = FrontendDataUtils.getVoices(this); 195 runOnUiThread(new Runnable(){ 196 public void run() { 197 voicesData.addAll(voicesDataNew); 198 ((ArrayAdapter<?>)voice.getAdapter()).notifyDataSetChanged(); 199 } 200 }); 201 202 final List<String> fortsDataNew = FrontendDataUtils.getForts(this); 203 runOnUiThread(new Runnable(){ 204 public void run() { 205 fortsData.addAll(fortsDataNew); 206 ((ArrayAdapter<?>)fort.getAdapter()).notifyDataSetChanged(); 207 } 208 }); 209 210 if(existingTeamName!=null) { 211 final Team loadedTeam = Team.load(Team.getTeamfileByName(getApplicationContext(), existingTeamName)); 212 if(loadedTeam==null) { 213 existingTeamName = null; 214 } else { 215 runOnUiThread(new Runnable(){ 216 public void run() { 217 setTeamValues(loadedTeam); 218 } 219 }); 220 } 221 } 222 runOnUiThread(new Runnable(){ 223 public void run() { 224 initComplete = true; 225 } 226 }); 227 } catch(FileNotFoundException e) { 228 this.runOnUiThread(new Runnable(){ 229 public void run() { 230 Toast.makeText(getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show(); 231 finish(); 232 } 233 }); 234 } 235 } 236 onDestroy()237 public void onDestroy() { 238 super.onDestroy(); 239 if (mp != null) { 240 mp.release(); 241 mp = null; 242 } 243 } 244 245 @Override onSaveInstanceState(Bundle outState)246 protected void onSaveInstanceState(Bundle outState) { 247 super.onSaveInstanceState(outState); 248 outState.putString(PARAMETER_EXISTING_TEAMNAME, existingTeamName); 249 } 250 onBackPressed()251 public void onBackPressed() { 252 if(initComplete) { 253 saveTeam(); 254 } 255 setResult(RESULT_OK); 256 super.onBackPressed(); 257 } 258 saveTeam()259 private void saveTeam() { 260 String teamName = name.getText().toString(); 261 String teamFlag = (String)((Map<String, Object>) flag.getSelectedItem()).get("txt"); 262 String teamFort = fort.getSelectedItem().toString(); 263 String teamGrave = (String)((Map<String, Object>) grave.getSelectedItem()).get("txt"); 264 String teamVoice = voice.getSelectedItem().toString(); 265 int levelInt = (Integer)((Map<String, Object>) difficulty.getSelectedItem()).get("level"); 266 267 List<Hog> hogs = new ArrayList<Hog>(); 268 for (int i = 0; i < hogName.size(); i++) { 269 String name = hogName.get(i).getText().toString(); 270 String hat = ((Map<String, Object>) hogHat.get(i).getSelectedItem()).get("txt").toString(); 271 hogs.add(new Hog(name, hat, levelInt)); 272 } 273 274 Team team = new Team(teamName, teamGrave, teamFlag, teamVoice, teamFort, hogs); 275 File teamsDir = new File(getFilesDir(), Team.DIRECTORY_TEAMS); 276 if (!teamsDir.exists()) teamsDir.mkdir(); 277 278 File newFile = Team.getTeamfileByName(this, teamName); 279 File oldFile = null; 280 if(existingTeamName != null) { 281 oldFile = Team.getTeamfileByName(this, existingTeamName); 282 } 283 try { 284 team.save(newFile); 285 // If the team was renamed, delete the old file. 286 if(oldFile != null && oldFile.isFile() && !oldFile.equals(newFile)) { 287 oldFile.delete(); 288 } 289 existingTeamName = teamName; 290 } catch(IOException e) { 291 Toast.makeText(getApplicationContext(), R.string.error_save_failed, Toast.LENGTH_SHORT).show(); 292 } 293 }; 294 295 private OnItemSelectedListener fortSelector = new OnItemSelectedListener() { 296 public void onItemSelected(AdapterView<?> arg0, View arg1, 297 int position, long arg3) { 298 String fortName = (String) arg0.getAdapter().getItem(position); 299 try { 300 File fortImage = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Forts", fortName, "L.png"); 301 Drawable fortIconDrawable = Drawable.createFromPath(fortImage.getAbsolutePath()); 302 imgFort.setImageDrawable(fortIconDrawable); 303 } catch(IOException e) { 304 Log.e(TAG, "Unable to show fort image", e); 305 } 306 scroller.fullScroll(ScrollView.FOCUS_DOWN);// Scroll the scrollview 307 // to the bottom, work 308 // around for scrollview 309 // invalidation (scrolls 310 // back to top) 311 } 312 313 public void onNothingSelected(AdapterView<?> arg0) { 314 } 315 316 }; 317 318 private OnClickListener voiceClicker = new OnClickListener() { 319 public void onClick(View v) { 320 try { 321 File dir = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Sounds", "voices", (String)voice.getSelectedItem()); 322 String file = ""; 323 File[] dirs = dir.listFiles(); 324 File f = dirs[(int) Math.round(Math.random() * dirs.length)]; 325 if (f.getName().endsWith(".ogg")) 326 file = f.getAbsolutePath(); 327 328 if (mp == null) 329 mp = new MediaPlayer(); 330 else 331 mp.reset(); 332 mp.setDataSource(file); 333 mp.prepare(); 334 mp.start(); 335 } catch (IllegalArgumentException e) { 336 Log.e(TAG, "Unable to play voice sample", e); 337 } catch (IllegalStateException e) { 338 Log.e(TAG, "Unable to play voice sample", e); 339 } catch (IOException e) { 340 Log.e(TAG, "Unable to play voice sample", e); 341 } 342 } 343 }; 344 345 @SuppressWarnings("unchecked") setTeamValues(Team t)346 private void setTeamValues(Team t){ 347 if (t == null) { 348 return; 349 } 350 351 try { 352 name.setText(t.name); 353 voice.setSelection(findPosition((ArrayAdapter<String>) voice.getAdapter(), t.voice)); 354 fort.setSelection(findPosition((ArrayAdapter<String>) fort.getAdapter(), t.fort)); 355 difficulty.setSelection(findPosition(typesData, "level", Integer.valueOf(t.hogs.get(0).level))); 356 grave.setSelection(findPosition(gravesData, "txt", t.grave)); 357 flag.setSelection(findPosition(flagsData, "txt", t.flag)); 358 359 for (int i = 0; i < Team.HEDGEHOGS_PER_TEAM; i++) { 360 hogHat.get(i).setSelection(findPosition(hatsData, "txt", t.hogs.get(i).hat)); 361 hogName.get(i).setText(t.hogs.get(i).name); 362 } 363 } catch(NoSuchElementException e) { 364 Toast.makeText(getApplicationContext(), R.string.error_team_attribute_not_found, Toast.LENGTH_LONG).show(); 365 finish(); 366 } 367 } 368 findPosition(ArrayAdapter<String> adapter, String value)369 int findPosition(ArrayAdapter<String> adapter, String value) throws NoSuchElementException { 370 int position = adapter.getPosition(value); 371 if(position<0) { 372 throw new NoSuchElementException(); 373 } 374 return position; 375 } 376 findPosition(List<? extends Map<String, ?>> data, String key, Object value)377 int findPosition(List<? extends Map<String, ?>> data, String key, Object value) throws NoSuchElementException { 378 int position = 0; 379 for (Map<String, ?> map : data) { 380 if (map.get(key).equals(value)) { 381 return position; 382 } 383 position++; 384 } 385 throw new NoSuchElementException(); 386 } 387 388 private SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() { 389 390 public boolean setViewValue(View view, Object data, 391 String textRepresentation) { 392 if (view instanceof ImageView && data instanceof Bitmap) { 393 ImageView v = (ImageView) view; 394 v.setImageBitmap((Bitmap) data); 395 return true; 396 } else { 397 return false; 398 } 399 } 400 }; 401 } 402