package org.expeditee.gui.management; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.stream.Collectors; import org.expeditee.agents.ExistingFramesetException; import org.expeditee.agents.InvalidFramesetNameException; import org.expeditee.core.Colour; import org.expeditee.core.Point; import org.expeditee.gui.Frame; import org.expeditee.gui.FrameIO; import org.expeditee.gui.MessageBay; import org.expeditee.items.Item; import org.expeditee.items.ItemUtils; import org.expeditee.items.Text; import org.expeditee.setting.Setting; import org.expeditee.settings.Settings; import org.expeditee.settings.UserSettings; import org.expeditee.settings.templates.TemplateSettings; public class ProfileManager { private static final String USER_NAME_PATTERN_INTERNAL = "USER.NAME"; private static final String DEFAULT = UserSettings.DEFAULT_PROFILE_NAME; private static final String[] startPages = { "exploratorysearch", "webbrowser" }; public static final String USER_NAME_PATTERN = "${" + USER_NAME_PATTERN_INTERNAL + "}"; public static Frame createProfile(String profileFor, Map specifiedSettings, Map> notifyWhenGenerated) { ensureDefaultProfile(); Frame profile = null; Frame profileOne = null; profileFor = FrameIO.ConvertToValidFramesetName(profileFor); try { profile = FrameIO.CreateFrameset(profileFor, FrameIO.PROFILE_PATH, true); profileOne = profile; profile.setTitle(profileFor + "'s Profile"); Frame defaultFrame = FrameIO.LoadFrame(DEFAULT + "1"); MessageBay.suppressMessages(true); UserSettings.UserName.set(profileFor); UserSettings.ProfileName.set(profileFor); int lastNumber = FrameIO.getLastNumber(defaultFrame.getFramesetName()); for (int i = 1; i <= lastNumber; i++) { // Load in next default, if it doesn't exist continue loop. defaultFrame = FrameIO.LoadFrame(DEFAULT + i); if (defaultFrame == null) { continue; } // Create the next next (currently blank) profile frame. // If there is frame gaps in the default (say if there is no 4.exp but there is // a 5.exp) then retain those gaps. // This way copied relative links work. while (profile.getNumber() < defaultFrame.getNumber()) { profile = FrameIO.CreateFrame(profile.getFramesetName(), null, null); } // Ensure we are working from a blank slate. profile.reset(); profile.removeAllItems(profile.getAllItems()); // For each item on defaultFrame: // 1. Set all items to be relatively linked so once copied their links correctly // point to the frame on the created profile rather than the default profile. // 2. Copy item from defaultFrame to the current profile frame being // constructed. // 3. Replace instance of ${USER.NAME} with 'profileFor' // 4. Replace settings values of copied items with those specified in // specifiedSettings (if present) Collection defaultAllItems = defaultFrame.getAllItems(); Collection allItems = new ArrayList(); for (Item item: defaultAllItems) { Item copyItem = item.copy(); allItems.add(copyItem); } profile.addAllItems(allItems); for (Item item: profile.getAllItems()) { if (item instanceof Text) { String content = item.getText(); item.setText(ResourceUtil.substitute(content, ProfileManager.USER_NAME_PATTERN_INTERNAL, profileFor)); } } String category = profile.getTitle(); List settingsKeys = null; if (specifiedSettings != null) { settingsKeys = specifiedSettings.keySet().stream().filter(key -> key.startsWith(category)).collect(Collectors.toList()); } if (settingsKeys != null) { for (String key: settingsKeys) { Setting setting = specifiedSettings.get(key); String name = setting.getName(); Text representation = setting.generateRepresentation(name, profile.getFramesetName()); Collection canditates = profile.getTextItems(); canditates.removeIf(text -> !text.getText().startsWith(representation.getText().split(" ")[0])); canditates.forEach(text -> { Point backupPos = text.getPosition(); Item.DuplicateItem(representation, text); text.setText(representation.getText()); text.setPosition(backupPos); }); } } if (notifyWhenGenerated != null && notifyWhenGenerated.containsKey(category)) { notifyWhenGenerated.get(category).accept(profile); } FrameIO.SaveFrame(profile); } MessageBay.suppressMessages(false); } catch (InvalidFramesetNameException | ExistingFramesetException e) { String preamble = "Failed to create profile for '" + DEFAULT + "'. "; if (e instanceof InvalidFramesetNameException) { String message = preamble + "Profile names must start and end with a letter and must contain only letters and numbers"; MessageBay.errorMessage(message); } else if (e instanceof ExistingFramesetException) { String message = preamble + "A frameset with this name already exists in: " + FrameIO.PROFILE_PATH; MessageBay.errorMessage(message); } } return profileOne; } /** * Checks if the default profile exists, creates it if it does not. */ public static void ensureDefaultProfile() { // If we can load in the default profile, we have nothing to do. Frame defaultFrame = FrameIO.LoadProfile(DEFAULT); if (defaultFrame != null) { return; } // We do not have a default profile, generate one. createDefaultProfile(); } /** * Creates the default profile. */ private static void createDefaultProfile() { try { Frame profile = FrameIO.CreateFrameset(DEFAULT, FrameIO.PROFILE_PATH, true); // Give the first frame in the new profile an appropriate title. Text titleItem = profile.getTitleItem(); if (titleItem != null) { titleItem.setText("Default Profile Frame"); } // initial position for placing items. int xPos = 300; int yPos = 100; // Add documentation links Path helpDirectory = Paths.get(FrameIO.HELP_PATH); File[] helpFramesets = helpDirectory.toFile().listFiles(); if (helpFramesets != null) { // Add the title for the help index Text helpPagesTitle = profile.addText(xPos, yPos, "@Expeditee Help", null); helpPagesTitle.setSize(25); helpPagesTitle.setFontStyle("Bold"); helpPagesTitle.setFamily("SansSerif"); helpPagesTitle.setColor(TemplateSettings.ColorWheel.get()[3]); xPos += 25; System.out.println("Installing frameset: "); boolean first_item = true; for (File helpFrameset : helpFramesets) { String framesetName = helpFrameset.getName(); if (!FrameIO.isValidFramesetName(framesetName)) { continue; } if (first_item) { System.out.print(" " + framesetName); first_item = false; } else { System.out.print(", " + framesetName); } System.out.flush(); Frame indexFrame = FrameIO.LoadFrame(framesetName + '1'); // Look through the folder for help index pages if (indexFrame != null && ItemUtils.FindTag(indexFrame.getSortedItems(), "@HelpIndex") != null) { // yPos += spacing; yPos += 30; Text helpLink = profile.addText(xPos, yPos, '@' + indexFrame.getFramesetName(), null); helpLink.setLink(indexFrame.getName()); helpLink.setColor(Colour.GREY); } } System.out.println(); } // Reset position xPos = 50; yPos = 100; // Add start pages Path framesetDirectory = Paths.get(FrameIO.FRAME_PATH); File[] startPageFramesets = framesetDirectory.toFile().listFiles(); if (startPageFramesets != null) { // Add Start Page title Text startPagesTitle = profile.addText(xPos, yPos, "@Start Pages", null); startPagesTitle.setSize(25); startPagesTitle.setFontStyle("Bold"); startPagesTitle.setFamily("SansSerif"); startPagesTitle.setColor(TemplateSettings.ColorWheel.get()[3]); xPos += 25; // Start Pages should be the first frame in its own frameset + // frameset name should be present in FrameUtils.startPages[]. for (File startpagesFrameset : startPageFramesets) { String framesetName = startpagesFrameset.getName(); // Only add link if frameset is a startpage for (int i = 0; i < startPages.length; i++) { if (framesetName.equals(startPages[i])) { Frame indexFrame = FrameIO.LoadFrame(framesetName + '1'); // Add start page link if (indexFrame != null) { yPos += 30; Text startPageLink = profile.addText(xPos, yPos, '@' + indexFrame.getFramesetName(), null); startPageLink.setLink(indexFrame.getName()); startPageLink.setColor(Colour.GREY); } } } } } // Add 'default' settings frameset Settings.Init(); Text settingsLink = profile.addText(550, 100, "@Settings", null); settingsLink.setSize((float) 25.0); settingsLink.setFamily("SansSerif"); settingsLink.setFontStyle("Bold"); settingsLink.setColor(Colour.GREY); Settings.generateSettingsTree(settingsLink); System.out.println("@Settings: Default settings generation complete."); FrameIO.SaveFrame(profile); int lastNumber = FrameIO.getLastNumber(profile.getFramesetName()); for (int i = 1; i <= lastNumber; i++) { Frame frame = FrameIO.LoadFrame(DEFAULT + i); frame.setOwner(DEFAULT); for(Item item: frame.getAllItems()) { item.setOwner(DEFAULT); item.setRelativeLink(); } frame.setChanged(true); FrameIO.SaveFrame(frame); } } catch (InvalidFramesetNameException | ExistingFramesetException e) { String preamble = "Failed to create profile for '" + DEFAULT + "'. "; if (e instanceof InvalidFramesetNameException) { String message = preamble + "Profile names must start and end with a letter and must contain only letters and numbers"; MessageBay.errorMessage(message); } else if (e instanceof ExistingFramesetException) { String message = preamble + "A frameset with this name already exists in: " + FrameIO.PROFILE_PATH; MessageBay.errorMessage(message); } return; } } }