/** * Update the conditions for dependent packages. Update the conditions for optional packages. * * @param initial indicates if its the first time updating conditions. */ private void updateConditions(boolean initial) { boolean changes = true; while (changes) { changes = false; for (Pack pack : packs) { String packName = pack.getName(); int pos = getPos(packName); logger.fine("Conditions fulfilled for: " + packName + "?"); if (!rules.canInstallPack(packName, variables)) { logger.fine("no"); if (rules.canInstallPackOptional(packName, variables)) { logger.fine("optional"); logger.fine(packName + " can be installed optionally."); if (initial) { if (checkValues[pos] != DESELECTED) { checkValues[pos] = DESELECTED; changes = true; } } } else { if (checkValues[pos] != DEPENDENT_DESELECTED) { logger.fine("Pack" + packName + " cannot be installed"); checkValues[pos] = DEPENDENT_DESELECTED; changes = true; } } } } } }
/** * This function updates the checkboxes after a change by disabling packs that cannot be installed * anymore and enabling those that can after the change. This is accomplished by running a search * that pinpoints the packs that must be disabled by a non-fullfiled dependency. TODO: Look into * "+2" and "-2", doesn't look safe */ protected void updateDeps() { int[] statusArray = new int[packs.size()]; for (int i = 0; i < statusArray.length; i++) { statusArray[i] = 0; } dfs(statusArray); for (int i = 0; i < statusArray.length; i++) { if (statusArray[i] == 0 && checkValues[i] < 0) { checkValues[i] += PARTIAL_SELECTED; } if (statusArray[i] == 1 && checkValues[i] >= 0) { checkValues[i] = DEPENDENT_DESELECTED; } } // The required ones must propagate their required status to all the ones that they depend on for (Pack pack : packs) { if (pack.isRequired()) { String name = pack.getName(); if (!(!rules.canInstallPack(name, variables) && rules.canInstallPackOptional(name, variables))) { checkValues = propRequirement(name, checkValues); } } } }
/** * Select/Deselect pack(s) based on packsData mapping. This is related to the onSelect and * onDeselect attributes for packs. User is not allowed to has a required pack for onSelect and * onDeselect. * * @param packsData */ private void selectionUpdate(Map<String, String> packsData) { RulesEngine rules = installData.getRules(); for (Map.Entry<String, String> packData : packsData.entrySet()) { int value, packPos; String packName = packData.getKey(); String condition = packData.getValue(); if (condition != null && !rules.isConditionTrue(condition)) { return; // Do nothing if condition is false } Pack pack; if (packName.startsWith("!")) { packName = packName.substring(1); pack = nameToPack.get(packName); packPos = getPos(packName); value = DESELECTED; } else { pack = nameToPack.get(packName); packPos = getPos(packName); value = SELECTED; } if (!pack.isRequired() && dependenciesResolved(pack)) { checkValues[packPos] = value; } } }
/** * Generate a map from a pack's name to its pack object. * * @param packs list of pack objects * @return map from a pack's name to its pack object. */ private Map<String, Pack> getNametoPackMapping(List<Pack> packs) { Map<String, Pack> nameToPack = new HashMap<String, Pack>(); for (Pack pack : packs) { nameToPack.put(pack.getName(), pack); } return nameToPack; }
/** * This function updates the checkboxes after a change by disabling packs that cannot be installed * anymore and enabling those that can after the change. This is accomplished by running a search * that pinpoints the packs that must be disabled by a non-fullfiled dependency. */ private void updateDeps() { int[] statusArray = new int[packs.size()]; for (int i = 0; i < statusArray.length; i++) { statusArray[i] = 0; } dfs(statusArray); for (int i = 0; i < statusArray.length; i++) { if (statusArray[i] == 0 && checkValues[i] < 0) { checkValues[i] += 2; } if (statusArray[i] == 1 && checkValues[i] >= 0) { checkValues[i] = -2; } } // The required ones must propagate their required status to all the // ones // that they depend on for (Pack pack : packs) { if (pack.isRequired()) { String packid = pack.getLangPackId(); if (packid != null) { if (!(!this.rules.canInstallPack(packid, this.variables) && this.rules.canInstallPackOptional(packid, this.variables))) { propRequirement(pack.getName()); } } else { propRequirement(pack.getName()); } } } }
/** * Set the value of the parent pack of the given pack to SELECTED, PARTIAL_SELECT, or DESELECTED. * Value of the pack is dependent of its children values. * * @param childPack */ private void updateParent(Pack childPack) { String parentName = childPack.getParent(); Pack parentPack = nameToPack.get(parentName); int parentPosition = nameToRow.get(parentName); int childrenSelected = 0; for (String childName : parentPack.getChildren()) { int childPosition = nameToRow.get(childName); if (isChecked(childPosition)) { childrenSelected += 1; } } if (parentPack.getChildren().size() == childrenSelected) { if (checkValues[parentPosition] < 0) { checkValues[parentPosition] = REQUIRED_SELECTED; } else { checkValues[parentPosition] = SELECTED; } } else if (childrenSelected > 0) { if (checkValues[parentPosition] < 0) { checkValues[parentPosition] = REQUIRED_PARTIAL_SELECTED; } else { checkValues[parentPosition] = PARTIAL_SELECTED; } } else { if (checkValues[parentPosition] < 0) { checkValues[parentPosition] = REQUIRED_DESELECTED; } else { checkValues[parentPosition] = DESELECTED; } } }
/** * Generate a map from a pack's name to its row number visible on the UI. * * @param packs list of pack objects * @return map from a pack's name to its row number visible on the UI */ private Map<String, Integer> getNametoRowMapping(List<Pack> packs) { Map<String, Integer> nameToPos = new HashMap<String, Integer>(); for (int i = 0; i < packs.size(); i++) { Pack pack = packs.get(i); nameToPos.put(pack.getName(), i); } return nameToPos; }
/** @return {@code true} if any dependencies for the visible packs exists else {@code false} */ public boolean dependenciesExist() { for (Pack pack : getVisiblePacks()) { if (pack.hasDependencies()) { return true; } } return false; }
/** @return a list of visible packs */ public List<Pack> getVisiblePacks() { List<Pack> visiblePacks = new ArrayList<Pack>(); for (Pack availablePack : installData.getAvailablePacks()) { if (!availablePack.isHidden()) { visiblePacks.add(availablePack); } } return visiblePacks; }
/** @return a list of hidden packs */ private List<Pack> getHiddenPacks() { List<Pack> hiddenPacks = new ArrayList<Pack>(); for (Pack availablePack : installData.getAvailablePacks()) { if (availablePack.isHidden()) { hiddenPacks.add(availablePack); } } return hiddenPacks; }
/** * Set the value of children packs to the same value as the parent pack. * * @param parentPack */ private void updateChildren(Pack parentPack) { String parentName = parentPack.getName(); int parentPosition = nameToRow.get(parentName); int parentValue = checkValues[parentPosition]; for (String childName : parentPack.getChildren()) { int childPosition = nameToRow.get(childName); checkValues[childPosition] = parentValue; } }
/** * Check if a pack's dependencies are resolved. * * @param pack * @return */ private boolean dependenciesResolved(Pack pack) { if (!pack.hasDependencies()) { return true; } for (String dependentPackName : pack.getDependencies()) { if (!isChecked(nameToRow.get(dependentPackName))) { return false; } } return true; }
private boolean isTrue(List<Pack> selectedpacks) { if (selectedpacks != null) { for (Pack selectedpack : selectedpacks) { if (name.equals(selectedpack.getName())) { // pack is selected return true; } } } // pack is not selected return false; }
/** @return the number of bytes that the installation requires based on selected packs */ public int getTotalByteSize() { Map<Pack, Integer> packToRow = getPacksToRowNumbers(); int row; int bytes = 0; for (Pack pack : packs) { row = packToRow.get(pack); if (isChecked(row)) { bytes += pack.getSize(); } } return bytes; }
/** * Remove pack that are already installed * * @param selectedPacks */ private void removeAlreadyInstalledPacks(List<Pack> selectedPacks) { List<Pack> removePacks = new ArrayList<Pack>(); for (Pack selectedPack : selectedPacks) { if (installedPacks.containsKey(selectedPack.getName())) { // pack is already installed, remove it removePacks.add(selectedPack); } } for (Pack removePack : removePacks) { selectedPacks.remove(removePack); } }
/* * @see TableModel#setValueAt(Object, int, int) * Update the value of some checkbox */ @Override public void setValueAt(Object checkValue, int rowIndex, int columnIndex) { if (columnIndex != 0 || !(checkValue instanceof Integer)) { return; } else { Pack pack = packs.get(rowIndex); boolean added; if ((Integer) checkValue == SELECTED) { added = true; String name = pack.getName(); if (rules.canInstallPack(name, variables) || rules.canInstallPackOptional(name, variables)) { if (pack.isRequired()) { checkValues[rowIndex] = REQUIRED_SELECTED; } else { checkValues[rowIndex] = SELECTED; } } } else { added = false; checkValues[rowIndex] = DESELECTED; } updateExcludes(rowIndex); updateDeps(); if (added) { onSelectionUpdate(rowIndex); this.packsToInstall.add(pack); // Temporarily add updateConditions(); this.packsToInstall.remove(pack); // Redo } else { onDeselectionUpdate(rowIndex); this.packsToInstall.remove(pack); // Temporarily remove updateConditions(); this.packsToInstall.add(pack); // Redo } updatePacksToInstall(); if (pack.hasParent()) { updateParent(pack); } else if (pack.hasChildren()) { updateChildren(pack); } fireTableDataChanged(); } }
/** * We use a modified dfs graph search algorithm as described in: Thomas H. Cormen, Charles * Leiserson, Ronald Rivest and Clifford Stein. Introduction to algorithms 2nd Edition 540-549,MIT * Press, 2001 */ private int dfs(int[] status) { Map<String, PackColor> colours = new HashMap<String, PackColor>(); for (int i = 0; i < packs.size(); i++) { for (Pack pack : packs) { colours.put(pack.getName(), PackColor.WHITE); } Pack pack = packs.get(i); boolean wipe = false; if (dfsVisit(pack, status, wipe, colours) != 0) { return -1; } } return 0; }
private Map<String, Pack> loadInstallationInformation(boolean modifyInstallation) { Map<String, Pack> installedpacks = new HashMap<String, Pack>(); if (!modifyInstallation) { return installedpacks; } // installation shall be modified // load installation information ObjectInputStream oin = null; try { FileInputStream fin = new FileInputStream( new File( installData.getInstallPath() + File.separator + InstallData.INSTALLATION_INFORMATION)); oin = new ObjectInputStream(fin); List<Pack> packsinstalled = (List<Pack>) oin.readObject(); for (Pack installedpack : packsinstalled) { installedpacks.put(installedpack.getName(), installedpack); } this.removeAlreadyInstalledPacks(installData.getSelectedPacks()); logger.fine("Found " + packsinstalled.size() + " installed packs"); Properties variables = (Properties) oin.readObject(); for (Object key : variables.keySet()) { installData.setVariable((String) key, (String) variables.get(key)); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (oin != null) { try { oin.close(); } catch (IOException e) { } } } return installedpacks; }
private void updateBytes() { long bytes = 0; for (int q = 0; q < packs.size(); q++) { if (Math.abs(checkValues[q]) == 1) { Pack pack = packs.get(q); bytes += pack.getSize(); } } // add selected hidden bytes for (Pack hidden : this.hiddenPacks) { if (this.rules.canInstallPack(hidden.getLangPackId(), variables)) { bytes += hidden.getSize(); } } panel.setBytes(bytes); }
/* * @see TableModel#getValueAt(int, int) */ @Override public Object getValueAt(int rowIndex, int columnIndex) { Pack pack = packs.get(rowIndex); switch (columnIndex) { case 0: return checkValues[rowIndex]; case 1: return PackHelper.getPackName(pack, messages); case 2: return Pack.toByteUnitsString(pack.getSize()); default: return null; } }
private int dfsVisit(Pack u, int[] status, boolean wipe, Map<String, PackColor> colours) { colours.put(u.getName(), PackColor.GREY); int check = checkValues[getPos(u.getName())]; if (Math.abs(check) != 1) { wipe = true; } List<String> deps = u.getDependants(); if (deps != null) { for (String name : deps) { Pack v = nameToPack.get(name); if (wipe) { status[getPos(v.getName())] = 1; } if (colours.get(v.getName()) == PackColor.WHITE) { final int result = dfsVisit(v, status, wipe, colours); if (result != 0) { return result; } } } } colours.put(u.getName(), PackColor.BLACK); return 0; }
/** * Ensure that parent packs know which packs are their children. Ensure that packs who have * dependants know which packs depend on them * * @param packs packs visible to the user * @param nameToPack mapping from pack names to pack objects * @return packs */ private List<Pack> setPackProperties(List<Pack> packs, Map<String, Pack> nameToPack) { Pack parent; for (Pack pack : packs) { if (pack.hasParent()) { String parentName = pack.getParent(); parent = nameToPack.get(parentName); parent.addChild(pack.getName()); } if (pack.hasDependencies()) { for (String name : pack.getDependencies()) { parent = nameToPack.get(name); parent.addDependant(pack.getName()); } } } return packs; }
/* * Sees which packs (if any) should be unchecked and updates checkValues */ protected void updateExcludes(int rowindex) { int value = checkValues[rowindex]; Pack pack = packs.get(rowindex); if (value > 0 && pack.getExcludeGroup() != null) { for (int q = 0; q < packs.size(); q++) { if (rowindex != q) { Pack otherPack = packs.get(q); String name1 = otherPack.getExcludeGroup(); String name2 = pack.getExcludeGroup(); if (name2.equals(name1)) { if (checkValues[q] == SELECTED) { checkValues[q] = DESELECTED; } } } } } }
private void removeAlreadyInstalledPacks(List<Pack> selectedpacks) { List<Pack> removepacks = new ArrayList<Pack>(); for (Pack selectedpack : selectedpacks) { String key = ""; if (selectedpack.getLangPackId() != null) { key = selectedpack.getLangPackId(); } else { key = selectedpack.getName(); } if (installedpacks.containsKey(key)) { // pack is already installed, remove it removepacks.add(selectedpack); } } for (Pack removepack : removepacks) { selectedpacks.remove(removepack); } }
/** * Initialize the data that represented the checkbox states. * * @param packs * @param packsToInstall * @return */ private int[] initCheckValues(List<Pack> packs, List<Pack> packsToInstall) { int[] checkValues = new int[packs.size()]; // If a pack is indicated to be installed checkbox value should be SELECTED for (int i = 0; i < packs.size(); i++) { Pack pack = packs.get(i); if (packsToInstall.contains(pack)) { checkValues[i] = SELECTED; } } // If a packs dependency cannot be resolved checkboc value should be DEPENDENT_DESELECTED for (int i = 0; i < packs.size(); i++) { Pack pack = packs.get(i); if (checkValues[i] == DESELECTED) { List<String> deps = pack.getDependants(); for (int j = 0; deps != null && j < deps.size(); j++) { String name = deps.get(j); int pos = getPos(name); checkValues[pos] = DEPENDENT_DESELECTED; } } // for mutual exclusion, uncheck uncompatible packs too // (if available in the current installGroup) if (checkValues[i] > 0 && pack.getExcludeGroup() != null) { for (int q = 0; q < packs.size(); q++) { if (q != i) { Pack otherPack = packs.get(q); if (pack.getExcludeGroup().equals(otherPack.getExcludeGroup())) { if (checkValues[q] == SELECTED) { checkValues[q] = DESELECTED; } } } } } } // Configure required packs for (Pack pack : packs) { if (pack.isRequired()) { checkValues = propRequirement(pack.getName(), checkValues); } } return checkValues; }
/** * Update packs to installed. A pack to be installed is: 1. A visible pack that has its checkbox * checked 2. A hidden pack that condition * * @return */ public List<Pack> updatePacksToInstall() { packsToInstall.clear(); for (int i = 0; i < packs.size(); i++) { Pack pack = packs.get(i); if (isChecked(i) && !installedPacks.containsKey(pack.getName())) { packsToInstall.add(pack); } else if (installedPacks.containsKey(pack.getName())) { checkValues[i] = REQUIRED_PARTIAL_SELECTED; } } for (Pack hiddenPack : this.hiddenPacks) { if (this.rules.canInstallPack(hiddenPack.getName(), variables)) { packsToInstall.add(hiddenPack); } } installData.setSelectedPacks(packsToInstall); return packsToInstall; }
@Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex == 0) { if (aValue instanceof Integer) { Pack pack = packs.get(rowIndex); boolean packadded = false; if ((Integer) aValue == 1) { packadded = true; String packid = pack.getLangPackId(); // TODO - see IZPACK-799 if (packid != null) { if (this.rules.canInstallPack(packid, this.variables) || this.rules.canInstallPackOptional(packid, this.variables)) { if (pack.isRequired()) { checkValues[rowIndex] = -1; } else { checkValues[rowIndex] = 1; } } } else { if (pack.isRequired()) { checkValues[rowIndex] = -1; } else { checkValues[rowIndex] = 1; } } } else { packadded = false; checkValues[rowIndex] = 0; } updateExcludes(rowIndex); updateDeps(); if (packadded) { if (panel.getDebugger() != null) { panel.getDebugger().packSelectionChanged("after adding pack " + pack.getLangPackId()); } // temporarily add pack to packstoinstall this.packsToInstall.add(pack); } else { if (panel.getDebugger() != null) { panel.getDebugger().packSelectionChanged("after removing pack " + pack.getLangPackId()); } // temporarily remove pack from packstoinstall this.packsToInstall.remove(pack); } updateConditions(); if (packadded) { // redo this.packsToInstall.remove(pack); } else { // redo this.packsToInstall.add(pack); } refreshPacksToInstall(); updateBytes(); fireTableDataChanged(); panel.showSpaceRequired(); } } }
/** Creates the reverse dependency graph */ private void reverseDeps() { // name to pack map namesObj = new HashMap<String, Pack>(); for (Pack pack : packs) { namesObj.put(pack.getName(), pack); } // process each pack for (Pack pack : packs) { List<String> deps = pack.getDependencies(); for (int j = 0; deps != null && j < deps.size(); j++) { String name = deps.get(j); Pack parent = namesObj.get(name); parent.addDependant(pack.getName()); } } }
@Override public boolean runConsole(InstallData installData, Console console) { java.util.List<Pack> selectedPacks = new ArrayList<Pack>(); String installationMode = null; do { installationMode = console.prompt("Do you to execute the defaut installation ? Y for yes, N for no", null); } while (!isGoodValue(installationMode)); if (isYes(installationMode)) { for (Pack p : installData.getAvailablePacks()) { if (p.isRequired() || p.isPreselected()) { selectedPacks.add(p); } } } else if (isNo(installationMode)) { for (Pack p : installData.getAvailablePacks()) { if (p.isRequired()) { selectedPacks.add(p); } else { String packToInstall = null; do { packToInstall = console.prompt( "Do you want to install [" + p.getName() + "] Y for yes, N for no ", null); } while (!isGoodValue(packToInstall)); if (isYes(packToInstall)) { selectedPacks.add(p); } else if (isNo(packToInstall)) { console.println("Installation of " + p.getName() + " skipped"); } } } } installData.setSelectedPacks(selectedPacks); return promptEndPanel(installData, console); }
private void updateConditions(boolean initial) { boolean changes = true; while (changes) { changes = false; // look for packages, for (Pack pack : packs) { int pos = getPos(pack.getName()); logger.fine("Conditions fulfilled for: " + pack.getName() + "?"); if (!this.rules.canInstallPack( pack.getLangPackId(), this.variables)) // TODO - see IZPACK-799 { logger.fine("no"); if (this.rules.canInstallPackOptional(pack.getLangPackId(), this.variables)) { logger.fine("optional"); logger.fine(pack.getLangPackId() + " can be installed optionally."); if (initial) { if (checkValues[pos] != 0) { checkValues[pos] = 0; changes = true; // let the process start from the beginning break; } } } else { logger.fine("Pack" + pack.getLangPackId() + " cannot be installed"); if (checkValues[pos] != -2) { checkValues[pos] = -2; changes = true; // let the process start from the beginning break; } } } } refreshPacksToInstall(); } }