/*
* Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
*
* This file is part of PowerFolder.
*
* PowerFolder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* PowerFolder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PowerFolder. If not, see <http://www.gnu.org/licenses/>.
*
* $Id$
*/
package de.dal33t.powerfolder.ui.wizard;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.BACKUP_ONLINE_STOARGE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.FOLDERINFO_ATTRIBUTE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.FOLDER_CREATE_ITEMS;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.FOLDER_IS_INVITE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.FOLDER_LOCAL_BASE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.MAKE_FRIEND_AFTER;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.PREVIEW_FOLDER_ATTIRBUTE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.SEND_INVIATION_AFTER_ATTRIBUTE;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.SET_DEFAULT_SYNCHRONIZED_FOLDER;
import static de.dal33t.powerfolder.ui.wizard.WizardContextAttributes.SYNC_PROFILE_ATTRIBUTE;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import de.dal33t.powerfolder.Constants;
import jwf.WizardPanel;
import de.dal33t.powerfolder.ConfigurationEntry;
import de.dal33t.powerfolder.Controller;
import de.dal33t.powerfolder.Member;
import de.dal33t.powerfolder.clientserver.ServerClient;
import de.dal33t.powerfolder.disk.Folder;
import de.dal33t.powerfolder.disk.FolderRepository;
import de.dal33t.powerfolder.disk.FolderSettings;
import de.dal33t.powerfolder.disk.SyncProfile;
import de.dal33t.powerfolder.light.FolderInfo;
import de.dal33t.powerfolder.light.MemberInfo;
import de.dal33t.powerfolder.util.FileUtils;
import de.dal33t.powerfolder.util.IdGenerator;
import de.dal33t.powerfolder.util.Reject;
import de.dal33t.powerfolder.util.StringUtils;
import de.dal33t.powerfolder.util.Translation;
import de.dal33t.powerfolder.util.UserDirectories;
import de.dal33t.powerfolder.util.os.Win32.ShellLink;
import de.dal33t.powerfolder.util.os.Win32.WinUtils;
/**
* A panel that actually starts the creation process of a folder on display.
* Automatically switches to the next panel when succeeded otherwise prints
* error.
* <p>
* Extracts the settings for the folder from the
* <code>WizardContextAttributes</code>.
*
* @author Christian Sprajc
* @version $Revision$
*/
public class FolderCreatePanel extends SwingWorkerPanel {
private static final Logger log = Logger.getLogger(FolderCreatePanel.class
.getName());
private boolean sendInvitations;
private final List<Folder> folders;
public FolderCreatePanel(Controller controller) {
super(controller, null, Translation
.getTranslation("wizard.create_folder.title"), Translation
.getTranslation("wizard.create_folder.working"), null);
setTask(new MyFolderCreateWorker());
folders = new ArrayList<Folder>();
}
@Override
protected String getTitle() {
return Translation.getTranslation("wizard.create_folder.title");
}
@Override
public boolean hasNext() {
return !folders.isEmpty();
}
@Override
public WizardPanel next() {
WizardPanel next;
if (sendInvitations) {
next = new SendInvitationsPanel(getController());
} else {
next = (WizardPanel) getWizardContext().getAttribute(
PFWizard.SUCCESS_PANEL);
}
return next;
}
private static FolderInfo createFolderInfo(File localBase) {
// Create new folder info
String name = FileUtils.getSuggestedFolderName(localBase);
String folderId = '[' + IdGenerator.makeId() + ']';
return new FolderInfo(name, folderId);
}
private class MyFolderCreateWorker implements Runnable {
public void run() {
Map<FolderInfo, FolderSettings> configurations = new HashMap<FolderInfo, FolderSettings>();
Map<FolderInfo, String> joinFolders = new HashMap<FolderInfo, String>();
// Preview folder
Object attribute = getWizardContext().getAttribute(
PREVIEW_FOLDER_ATTIRBUTE);
boolean previewFolder = false;
if (attribute != null && attribute instanceof Boolean) {
previewFolder = (Boolean) attribute;
}
// Online storage
attribute = getWizardContext().getAttribute(BACKUP_ONLINE_STOARGE);
boolean backupByOS = false;
if (attribute != null && attribute instanceof Boolean) {
backupByOS = (Boolean) attribute;
}
if (backupByOS) {
getController().getUIController().getApplicationModel()
.getServerClientModel().checkAndSetupAccount();
}
// Send invitation after
attribute = getWizardContext().getAttribute(
SEND_INVIATION_AFTER_ATTRIBUTE);
sendInvitations = false;
if (attribute != null && attribute instanceof Boolean) {
sendInvitations = (Boolean) attribute;
}
// Either we have FOLDER_CREATE_ITEMS ...
List<FolderCreateItem> folderCreateItems = (List<FolderCreateItem>) getWizardContext()
.getAttribute(FOLDER_CREATE_ITEMS);
if (folderCreateItems != null && !folderCreateItems.isEmpty()) {
for (FolderCreateItem folderCreateItem : folderCreateItems) {
File localBase = folderCreateItem.getLocalBase();
Reject.ifNull(localBase,
"Local base for folder is null/not set");
SyncProfile syncProfile = folderCreateItem.getSyncProfile();
if (syncProfile == null) {
syncProfile = SyncProfile.getDefault(getController());
}
FolderInfo folderInfo = folderCreateItem.getFolderInfo();
if (folderInfo == null) {
folderInfo = createFolderInfo(localBase);
}
int archiveHistory = folderCreateItem.getArchiveHistory();
if (!StringUtils.isBlank(folderCreateItem
.getLinkToOnlineFolder()))
{
joinFolders.put(folderInfo,
folderCreateItem.getLinkToOnlineFolder());
}
FolderSettings folderSettings = new FolderSettings(
localBase, syncProfile, false,
previewFolder, null, archiveHistory, true);
configurations.put(folderInfo, folderSettings);
}
} else {
// ... or FOLDER_LOCAL_BASE + SYNC_PROFILE_ATTRIBUTE + optional
// FOLDERINFO_ATTRIBUTE...
File localBase = (File) getWizardContext().getAttribute(
FOLDER_LOCAL_BASE);
Reject.ifNull(localBase,
"Local base for folder is null/not set");
SyncProfile syncProfile = (SyncProfile) getWizardContext()
.getAttribute(SYNC_PROFILE_ATTRIBUTE);
if (syncProfile == null) {
syncProfile = SyncProfile.getDefault(getController());
}
// Optional
FolderInfo folderInfo = (FolderInfo) getWizardContext()
.getAttribute(FOLDERINFO_ATTRIBUTE);
if (folderInfo == null) {
folderInfo = createFolderInfo(localBase);
}
FolderSettings folderSettings = new FolderSettings(localBase,
syncProfile, false,
previewFolder, null,
ConfigurationEntry.DEFAULT_ARCHIVE_VERSIONS
.getValueInt(getController()), true);
configurations.put(folderInfo, folderSettings);
}
// Reset
folders.clear();
updateButtons();
ServerClient client = getController().getOSClient();
Collection<FolderInfo> onlineFolderInfos = client
.getAccountFolders();
for (Map.Entry<FolderInfo, FolderSettings> entry : configurations
.entrySet())
{
FolderInfo folderInfo = entry.getKey();
FolderSettings folderSettings = entry.getValue();
String joinFolderName = joinFolders.get(folderInfo);
if (joinFolderName == null) {
// Don't try to join online folders by name if this is an
// invite. Invites always join the invite folder.
Boolean folderIsInvite = (Boolean) getWizardContext()
.getAttribute(FOLDER_IS_INVITE);
if (folderIsInvite == null || !folderIsInvite) {
// Look for folders where there is already an online
// folder with the same name. Join instead of creating
// duplicates.
for (FolderInfo onlineFolderInfo : onlineFolderInfos) {
if (onlineFolderInfo.getName().equals(
folderInfo.getName()))
{
if (!onlineFolderInfo.equals(folderInfo)) {
log.info("Found online folder with same name: "
+ folderInfo.getName() + ". Using it");
// User actually wants to join, so use
// online.
folderInfo = onlineFolderInfo;
log.info("Changed folder info to online version: "
+ folderInfo.getName());
break;
}
}
}
}
} else {
// User already specified online folder to join - join it.
boolean gotIt = false;
for (FolderInfo onlineFolderInfo : onlineFolderInfos) {
if (onlineFolderInfo.getName().equals(joinFolderName)) {
log.info("Joining specified folder "
+ joinFolderName);
folderInfo = onlineFolderInfo;
gotIt = true;
break;
}
}
if (!gotIt) {
// Hmmm - link folder specified but can not find it now?
log.warning("Could not find link folder "
+ joinFolderName + " for " + folderInfo);
}
}
Folder folder = getController().getFolderRepository()
.createFolder(folderInfo, folderSettings);
folder.addDefaultExcludes();
createShortcutToFolder(folderInfo, folderSettings);
folders.add(folder);
if (configurations.size() == 1) {
// Set for SendInvitationsPanel
getWizardContext().setAttribute(FOLDERINFO_ATTRIBUTE,
folder.getInfo());
}
// Is there a member to make a friend?
// Invitation invitors are automatically made friends.
attribute = getWizardContext().getAttribute(
MAKE_FRIEND_AFTER);
if (attribute != null && attribute instanceof MemberInfo) {
MemberInfo memberInfo = (MemberInfo) attribute;
Member member = getController().getNodeManager().getNode(
memberInfo);
if (member != null) {
if (!member.isFriend()) {
member.setFriend(true, null);
}
}
}
if (backupByOS && client.isLoggedIn()) {
// Try to back this up by online storage.
if (client.joinedByCloud(folder)) {
// Already have this os folder.
log.log(Level.WARNING, "Already have os folder "
+ folderInfo.name);
continue;
}
client.getFolderService().createFolder(folderInfo, null);
// Set as default synced folder?
attribute = getWizardContext().getAttribute(
SET_DEFAULT_SYNCHRONIZED_FOLDER);
if (attribute != null && (Boolean) attribute) {
// TODO: Ugly. Use abstraction: Runnable? Callback
// with
// folder? Which is placed on WizardContext.
client.getFolderService().setDefaultSynchronizedFolder(
folderInfo);
createDefaultFolderHelpFile(folder);
folder.recommendScanOnNextMaintenance();
FileUtils.openFile(folder.getLocalBase());
}
}
}
}
private void createShortcutToFolder(FolderInfo folderInfo,
FolderSettings folderSettings)
{
FolderRepository folderRepo = getController().getFolderRepository();
File baseDir = folderRepo.getFoldersBasedir();
if (!baseDir.exists()) {
log.info(String.format("Creating basedir: %s",
baseDir.getAbsolutePath()));
baseDir.mkdirs();
}
File existingFolder = new File(baseDir, folderInfo.name);
if (existingFolder.exists()) {
log.finer("Folder is an existing subdirectory in basedir: "
+ existingFolder);
return;
}
File shortcutFile = new File(baseDir, folderInfo.getName() + Constants.LINK_EXTENSION);
String shortcutPath = shortcutFile.getAbsolutePath();
String filePath = folderSettings.getLocalBaseDir()
.getAbsolutePath();
if (WinUtils.isSupported()
&& !UserDirectories.getUserDirectories().containsKey(
folderInfo.getName()))
{
WinUtils winUtils = WinUtils.getInstance();
ShellLink shellLink = new ShellLink(null, null, filePath, null);
try {
log.info(String.format(
"Attempting to create shortcut %s to %s", shortcutPath,
filePath));
winUtils.createLink(shellLink, shortcutPath);
} catch (IOException e) {
log.warning(String
.format(
"An exception was thrown when creating shortcut %s to %s",
shortcutPath, filePath));
}
}
}
private void createDefaultFolderHelpFile(Folder folder) {
File helpFile = new File(folder.getLocalBase(),
"Place files to sync here.txt");
if (helpFile.exists()) {
return;
}
Writer w = null;
try {
w = new OutputStreamWriter(new FileOutputStream(helpFile));
w.write("This is the default synchronized folder of PowerFolder.\r\n");
w.write("Simply place files into this directory to sync them\r\n");
w.write("across all your computers running PowerFolder.\r\n");
w.write("\r\n");
w.write("More information: http://wiki.powerfolder.com/wiki/Default_Folder");
w.close();
} catch (IOException e) {
// Doesn't matter.
} finally {
if (w != null) {
try {
w.close();
} catch (IOException e) {
// Ignore
}
}
}
}
}
}