protected void generateCode() {
		List<Invalid> errors = validateData();
		if (!errors.isEmpty()) {
			displayValidationErrorDialog(true, errors);
			return;
		}

		JFileChooser save = new JFileChooser();
		save.setAcceptAllFileFilterUsed(false);
		save.setFileFilter(new FileNameExtensionFilter("JAR files", "jar"));
		int result = save.showSaveDialog(this);
		if (result != JFileChooser.APPROVE_OPTION) {
			return;
		}

		File selected = save.getSelectedFile();
		if (!selected.getName().toLowerCase().endsWith(".jar")) {
			selected = new File(selected.getAbsolutePath() + ".jar");
		}

		final Map<Aspect, ProgressIndicator> boxes = new LinkedHashMap<>();
		boxes.put(Aspect.GENERAL, new ProgressIndicator(
				"Generating general and shop code"));
		boxes.put(Aspect.LEVELS, new ProgressIndicator("Generating level code"));
		boxes.put(Aspect.TOWERS, new ProgressIndicator("Generating tower code"));
		boxes.put(Aspect.ENEMIES,
				new ProgressIndicator("Generating enemy code"));
		boxes.put(Aspect.PROJECTILES, new ProgressIndicator(
				"Generating projectile code"));
		boxes.put(null, new ProgressIndicator("Compiling and packaging code"));

		final JPanel pnlDialog = new JPanel(new MigLayout());

		JLabel lblTitle = new JLabel("Code generation in progress.");
		JLabel lblSubtitle = new JLabel("Please wait...");
		lblTitle.setFont(lblTitle.getFont().deriveFont(24f)
				.deriveFont(Font.BOLD));
		lblSubtitle.setFont(lblSubtitle.getFont().deriveFont(18f));

		CC labels = new CC().growX().pushX().wrap(); // looks nicer without span

		pnlDialog.add(lblTitle, labels);
		pnlDialog.add(lblSubtitle, labels);
		pnlDialog.add(new JSeparator(JSeparator.HORIZONTAL), new CC().growX()
				.pushX().spanX());

		for (ProgressIndicator indicator : boxes.values()) {
			indicator.addTo(pnlDialog);
		}

		JProgressBar pb = new JProgressBar();
		pb.setIndeterminate(true);
		pnlDialog.add(pb, new CC().newline().growX().pushX().spanX());

		final JDialog dialog = new JDialog(TowerDefGen.this,
				"Code Generation Progress");
		dialog.setContentPane(pnlDialog);
		dialog.pack();
		dialog.setLocationRelativeTo(TowerDefGen.this);
		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		dialog.setVisible(true);
		dialog.setModal(true);

		final File finalFile = selected;
		new Thread(new Runnable() {
			@Override
			public void run() {
				CodeGenerator.generateJar(getDataObject(), finalFile,
						new CodeProgress() {
							private CodeGenerationState lastState = null;

							@Override
							public void progressUpdated(
									CodeGenerationState newState) {
								if (lastState != null) {
									boxes.get(lastState.aspect).setState(
											ProgressState.COMPLETED);
								}
								lastState = newState;
								boxes.get(newState.aspect).setState(
										ProgressState.IN_PROGRESS);
							}

						});
				dialog.setVisible(false);
				dialog.dispose();

				int ret = JOptionPane
						.showConfirmDialog(
								TowerDefGen.this,
								"Your game has been exported. Would you like to launch it now?",
								"Export Complete", JOptionPane.YES_NO_OPTION);
				if (ret == JOptionPane.YES_OPTION) {
					ProcessBuilder pb = new ProcessBuilder("java", "-jar",
							finalFile.getAbsolutePath());
					try {
						pb.start();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

	}