/**
* Copyright 2011 multibit.org
*
* Licensed under the MIT license (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/mit-license.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.multibit.viewsystem.swing.action;
import com.googlecode.jcsv.CSVStrategy;
import com.googlecode.jcsv.writer.CSVWriter;
import com.googlecode.jcsv.writer.internal.CSVWriterBuilder;
import org.multibit.controller.Controller;
import org.multibit.controller.bitcoin.BitcoinController;
import org.multibit.file.WalletTableDataEntryConverter;
import org.multibit.file.WalletTableDataHeaderEntryConverter;
import org.multibit.message.Message;
import org.multibit.message.MessageManager;
import org.multibit.model.bitcoin.BitcoinModel;
import org.multibit.model.bitcoin.WalletData;
import org.multibit.model.bitcoin.WalletTableData;
import org.multibit.utils.ImageLoader;
import org.multibit.viewsystem.swing.MultiBitFrame;
import org.multibit.viewsystem.swing.view.CsvFileFilter;
import org.multibit.viewsystem.swing.view.components.FontSizer;
import org.multibit.viewsystem.swing.view.panels.HelpContentsPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/**
* This {@link Action} exports transactions from a wallet.
*/
public class ExportTransactionsSubmitAction extends AbstractAction {
private static final Logger log = LoggerFactory.getLogger(CreateWalletSubmitAction.class);
private static final long serialVersionUID = 1923492460523457765L;
private final Controller controller;
private final BitcoinController bitcoinController;
private MultiBitFrame mainFrame;
private Font adjustedFont;
/**
* Creates a new {@link ExportTransactionsSubmitAction}.
*/
public ExportTransactionsSubmitAction(BitcoinController bitcoinController, MultiBitFrame mainFrame) {
super(bitcoinController.getLocaliser().getString("exportTransactionsSubmitAction.text"), ImageLoader.createImageIcon(ImageLoader.TRANSACTIONS_EXPORT_ICON_FILE));
this.bitcoinController = bitcoinController;
this.controller = this.bitcoinController;
this.mainFrame = mainFrame;
MnemonicUtil mnemonicUtil = new MnemonicUtil(controller.getLocaliser());
putValue(SHORT_DESCRIPTION, HelpContentsPanel.createTooltipTextForMenuItem(controller.getLocaliser().getString("exportTransactionsSubmitAction.tooltip")));
putValue(MNEMONIC_KEY, mnemonicUtil.getMnemonic("exportTransactionsSubmitAction.text"));
}
/**
* Ask the user for a filename and then export transactions to there.
*/
@Override
public void actionPerformed(ActionEvent e) {
if (mainFrame != null) {
mainFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
setEnabled(false);
try {
// Create a file save dialog.
JFileChooser.setDefaultLocale(controller.getLocaliser().getLocale());
JFileChooser fileChooser = new JFileChooser();
fileChooser.setLocale(controller.getLocaliser().getLocale());
fileChooser.setDialogTitle( controller.getLocaliser().getString("showExportPrivateKeysPanel.filename.text.2"));
adjustedFont = FontSizer.INSTANCE.getAdjustedDefaultFont();
if (adjustedFont != null) {
setFileChooserFont(new Container[] {fileChooser});
}
String walletFilename = bitcoinController.getModel().getActiveWalletFilename();
fileChooser.applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
if (walletFilename != null) {
fileChooser.setCurrentDirectory(new File(walletFilename));
}
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setFileFilter(new CsvFileFilter(controller));
String defaultFileName;
if (walletFilename != null) {
// Find stem of filename.
int suffixSeparatorLong = walletFilename.lastIndexOf('.');
String stem = walletFilename.substring(0, suffixSeparatorLong);
defaultFileName = stem + "." + BitcoinModel.CSV_FILE_EXTENSION;
} else {
defaultFileName = fileChooser.getCurrentDirectory().getAbsoluteFile() + File.separator
+ controller.getLocaliser().getString("saveWalletAsView.untitled") + "." + BitcoinModel.CSV_FILE_EXTENSION;
}
fileChooser.setSelectedFile(new File(defaultFileName));
fileChooser.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
int returnVal = fileChooser.showSaveDialog(mainFrame);
String exportTransactionsFilename = null;
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
if (file != null) {
exportTransactionsFilename = file.getAbsolutePath();
exportTransactions(exportTransactionsFilename);
}
}
} finally {
setEnabled(true);
if (mainFrame != null) {
mainFrame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
void exportTransactions(String exportTransactionsFilename) {
String message;
if (new File(exportTransactionsFilename).isDirectory()) {
message = controller.getLocaliser().getString("exportTransactionsSubmitAction.fileIsADirectory",
new Object[] { exportTransactionsFilename });
log.debug(message);
MessageManager.INSTANCE.addMessage(new Message(message));
return;
}
// If the filename has no extension, put on the wallet extension.
if (!exportTransactionsFilename.contains(".")) {
exportTransactionsFilename = exportTransactionsFilename + "." + BitcoinModel.CSV_FILE_EXTENSION;
}
File exportTransactionsFile = new File(exportTransactionsFilename);
// Check on file overwrite.
if (exportTransactionsFile.exists()) {
String yesText = controller.getLocaliser().getString("showOpenUriView.yesText");
String noText = controller.getLocaliser().getString("showOpenUriView.noText");
String questionText = controller.getLocaliser().getString("showExportPrivateKeysAction.thisFileExistsOverwrite",
new Object[] { exportTransactionsFile.getName() });
String questionTitle = controller.getLocaliser().getString("showExportPrivateKeysAction.thisFileExistsOverwriteTitle");
int selection = JOptionPane.showOptionDialog(mainFrame, questionText, questionTitle, JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, ImageLoader.createImageIcon(ImageLoader.QUESTION_MARK_ICON_FILE), new String[] {
yesText, noText }, noText);
if (selection != JOptionPane.YES_OPTION) {
return;
}
// Delete the existing file.
boolean deleteWasSuccessful = exportTransactionsFile.delete();
if (!deleteWasSuccessful) {
String message2 = controller.getLocaliser().getString("exportTransactionsSubmitAction.genericCouldNotDelete",
new Object[] { exportTransactionsFilename});
log.error(message2);
MessageManager.INSTANCE.addMessage(new Message(message2));
return;
}
}
// Now actually perform the export.
// (This is separated out to make it easier to test.)
exportTransactionsDoIt(bitcoinController.getModel().getActivePerWalletModelData(), exportTransactionsFilename);
}
private void setFileChooserFont(Component[] comp) {
for (int x = 0; x < comp.length; x++) {
if (comp[x] instanceof Container)
setFileChooserFont(((Container) comp[x]).getComponents());
try {
comp[x].setFont(adjustedFont);
} catch (Exception e) {
}// do nothing
}
}
public void exportTransactionsDoIt(WalletData walletData, String exportTransactionsFilename) {
List<WalletTableData> walletTableDataList = bitcoinController.getModel().createWalletTableData(bitcoinController, walletData);
// Sort by date descending.
Comparator<WalletTableData> comparator = new Comparator<WalletTableData>() {
@Override
public int compare(WalletTableData o1, WalletTableData o2) {
if (o1 == null) {
if (o2 == null) {
return 0;
} else {
return 1;
}
} else {
if (o2 == null) {
return -1;
}
}
Date d1 = o1.getDate();
Date d2 = o2.getDate();
if (d1 == null) {
// Object 1 has missing date.
return 1;
}
if (d2 == null) {
// Object 2 has missing date.
return -1;
}
long n1 = d1.getTime();
long n2 = d2.getTime();
if (n1 == 0) {
// Object 1 has missing date.
return 1;
}
if (n2 == 0) {
// Object 2 has missing date.
return -1;
}
if (n1 < n2) {
return -1;
} else if (n1 > n2) {
return 1;
} else {
return 0;
}
}
};
Collections.sort(walletTableDataList, Collections.reverseOrder(comparator));
//Writer out = null;
OutputStreamWriter outputStreamWriter = null;
try {
//out = new FileWriter(exportTransactionsFilename);
outputStreamWriter = new OutputStreamWriter ( new FileOutputStream(exportTransactionsFilename, true ), "UTF-8" );
// Write the header row.
WalletTableDataHeaderEntryConverter headerConverter = new WalletTableDataHeaderEntryConverter();
headerConverter.setBitcoinController(bitcoinController);
CSVWriter<WalletTableData> csvHeaderWriter = new CSVWriterBuilder<WalletTableData>(outputStreamWriter).strategy(CSVStrategy.UK_DEFAULT)
.entryConverter(headerConverter).build();
csvHeaderWriter.write(new WalletTableData(null));
// Write the body of the CSV file.
WalletTableDataEntryConverter converter = new WalletTableDataEntryConverter();
converter.setBitcoinController(bitcoinController);
CSVWriter<WalletTableData> csvWriter = new CSVWriterBuilder<WalletTableData>(outputStreamWriter).strategy(CSVStrategy.UK_DEFAULT)
.entryConverter(converter).build();
csvWriter.writeAll(walletTableDataList);
String message = controller.getLocaliser().getString("exportTransactionsSubmitAction.success",
new Object[] { exportTransactionsFilename });
MessageManager.INSTANCE.addMessage(new Message(message));
} catch (NullPointerException e) {
String message = controller.getLocaliser().getString("exportTransactionsSubmitAction.failure",
new Object[] { exportTransactionsFilename, e.getClass().getName() });
log.error(message);
MessageManager.INSTANCE.addMessage(new Message(message));
} catch (IOException e) {
String message = controller.getLocaliser().getString("exportTransactionsSubmitAction.failure",
new Object[] { exportTransactionsFilename, e.getMessage() });
log.error(message);
MessageManager.INSTANCE.addMessage(new Message(message));
} finally {
if (outputStreamWriter != null) {
try {
outputStreamWriter.flush();
outputStreamWriter.close();
} catch (IOException ioe) {
String message = controller.getLocaliser().getString("exportTransactionsSubmitAction.failure",
new Object[] { exportTransactionsFilename, ioe.getMessage() });
log.error(message);
MessageManager.INSTANCE.addMessage(new Message(message));
}
}
}
}
}