summaryrefslogtreecommitdiffstats
path: root/src/app/Dialogs/checksumdlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/Dialogs/checksumdlg.cpp')
-rw-r--r--src/app/Dialogs/checksumdlg.cpp603
1 files changed, 603 insertions, 0 deletions
diff --git a/src/app/Dialogs/checksumdlg.cpp b/src/app/Dialogs/checksumdlg.cpp
new file mode 100644
index 0000000..26e5c7b
--- /dev/null
+++ b/src/app/Dialogs/checksumdlg.cpp
@@ -0,0 +1,603 @@
+#include "checksumdlg.h"
+#include "../krusader.h"
+#include <tdelocale.h>
+#include <tqlayout.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <klineedit.h>
+#include <tdelistview.h>
+#include <tqpixmap.h>
+#include <kcursor.h>
+#include <tdemessagebox.h>
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <tdefiledialog.h>
+#include <tqframe.h>
+#include <kiconloader.h>
+#include <kcombobox.h>
+#include <tqfileinfo.h>
+#include <kurlrequester.h>
+#include "../krservices.h"
+#include <tqptrlist.h>
+#include <tqmap.h>
+#include <tdetempfile.h>
+#include <tdestandarddirs.h>
+
+class CS_Tool; // forward
+typedef void PREPARE_PROC_FUNC(TDEProcess& proc, CS_Tool *self, const TQStringList& files,
+ const TQString checksumFile, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString& type);
+typedef TQStringList GET_FAILED_FUNC(const TQStringList& stdOut, const TQStringList& stdErr);
+
+class CS_Tool {
+public:
+ enum Type {
+ MD5=0, SHA1, SHA256, TIGER, WHIRLPOOL, SFV, CRC,
+ SHA224, SHA384, SHA512,
+ NumOfTypes
+ };
+
+ Type type;
+ TQString binary;
+ bool recursive;
+ bool standardFormat;
+ PREPARE_PROC_FUNC *create, *verify;
+ GET_FAILED_FUNC *failed;
+};
+
+class CS_ToolByType {
+public:
+ TQPtrList<CS_Tool> tools, r_tools; // normal and recursive tools
+};
+
+// handles md5sum and sha1sum
+void sumCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files,
+ const TQString, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString&) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary );
+ Q_ASSERT(!recursive);
+ proc << files << "1>" << stdoutFileName << "2>" << stderrFileName;
+}
+
+void sumVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& /* files */,
+ const TQString checksumFile, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString& /* type */) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary );
+ Q_ASSERT(!recursive);
+ proc << "-c" << checksumFile << "1>" << stdoutFileName << "2>" << stderrFileName;
+}
+
+TQStringList sumFailedFunc(const TQStringList& stdOut, const TQStringList& stdErr) {
+ // md5sum and sha1sum print "...: FAILED" for failed files and display
+ // the number of failures to stderr. so if stderr is empty, we'll assume all is ok
+ TQStringList result;
+ if (stdErr.size()==0) return result;
+ result += stdErr;
+ // grep for the ":FAILED" substring
+ const TQString tmp = TQString(": FAILED").local8Bit();
+ for (uint i=0; i<stdOut.size();++i) {
+ if (stdOut[i].find(tmp) != -1)
+ result += stdOut[i];
+ }
+
+ return result;
+}
+
+// handles *deep binaries
+void deepCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files,
+ const TQString, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString&) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary );
+ if (recursive) proc << "-r";
+ proc << "-l" << files << "1>" << stdoutFileName << "2>" << stderrFileName;
+}
+
+void deepVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files,
+ const TQString checksumFile, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString&) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary );
+ if (recursive) proc << "-r";
+ proc << "-x" << checksumFile << files << "1>" << stdoutFileName << "2>" << stderrFileName;
+}
+
+TQStringList deepFailedFunc(const TQStringList& stdOut, const TQStringList&/* stdErr */) {
+ // *deep dumps (via -x) all failed hashes to stdout
+ return stdOut;
+}
+
+// handles cfv binary
+void cfvCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files,
+ const TQString, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString& type) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary ) << "-C" << "-VV";
+ if (recursive) proc << "-rr";
+ proc << "-t" << type << "-f-" << "-U" << files << "1>" << stdoutFileName << "2>" << stderrFileName;
+}
+
+void cfvVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& /* files */,
+ const TQString checksumFile, bool recursive, const TQString& stdoutFileName,
+ const TQString& stderrFileName, const TQString&type) {
+ proc.setUseShell(true, "/bin/bash");
+ proc << KrServices::fullPathName( self->binary ) << "-M";
+ if (recursive) proc << "-rr";
+ proc << "-U" << "-VV" << "-t" << type << "-f" << checksumFile << "1>" << stdoutFileName << "2>" << stderrFileName;// << files;
+}
+
+TQStringList cfvFailedFunc(const TQStringList& /* stdOut */, const TQStringList& stdErr) {
+ // cfv dumps all failed hashes to stderr
+ return stdErr;
+}
+
+// important: this table should be ordered like so that all md5 tools should be
+// one after another, and then all sha1 and so on and so forth. they tools must be grouped,
+// since the code in getTools() counts on it!
+CS_Tool cs_tools[] = {
+ // type binary recursive stdFmt create_func verify_func failed_func
+ {CS_Tool::MD5, "md5sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::MD5, "md5deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc},
+ {CS_Tool::MD5, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc},
+ {CS_Tool::SHA1, "sha1sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::SHA1, "sha1deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc},
+ {CS_Tool::SHA1, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc},
+ {CS_Tool::SHA224, "sha224sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::SHA256, "sha256sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::SHA256, "sha256deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc},
+ {CS_Tool::SHA384, "sha384sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::SHA512, "sha512sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc},
+ {CS_Tool::TIGER, "tigerdeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc},
+ {CS_Tool::WHIRLPOOL, "whirlpooldeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc},
+ {CS_Tool::SFV, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc},
+ {CS_Tool::CRC, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc},
+};
+
+TQMap<TQString, CS_Tool::Type> cs_textToType;
+TQMap<CS_Tool::Type, TQString> cs_typeToText;
+
+void initChecksumModule() {
+ // prepare the dictionaries - pity it has to be manually
+ cs_textToType["md5"]=CS_Tool::MD5;
+ cs_textToType["sha1"]=CS_Tool::SHA1;
+ cs_textToType["sha256"]=CS_Tool::SHA256;
+ cs_textToType["sha224"]=CS_Tool::SHA224;
+ cs_textToType["sha384"]=CS_Tool::SHA384;
+ cs_textToType["sha512"]=CS_Tool::SHA512;
+ cs_textToType["tiger"]=CS_Tool::TIGER;
+ cs_textToType["whirlpool"]=CS_Tool::WHIRLPOOL;
+ cs_textToType["sfv"]=CS_Tool::SFV;
+ cs_textToType["crc"]=CS_Tool::CRC;
+
+ cs_typeToText[CS_Tool::MD5]="md5";
+ cs_typeToText[CS_Tool::SHA1]="sha1";
+ cs_typeToText[CS_Tool::SHA256]="sha256";
+ cs_typeToText[CS_Tool::SHA224]="sha224";
+ cs_typeToText[CS_Tool::SHA384]="sha384";
+ cs_typeToText[CS_Tool::SHA512]="sha512";
+ cs_typeToText[CS_Tool::TIGER]="tiger";
+ cs_typeToText[CS_Tool::WHIRLPOOL]="whirlpool";
+ cs_typeToText[CS_Tool::SFV]="sfv";
+ cs_typeToText[CS_Tool::CRC]="crc";
+
+ // build the checksumFilter (for usage in KRQuery)
+ TQMap<TQString, CS_Tool::Type>::Iterator it;
+ for (it=cs_textToType.begin(); it!=cs_textToType.end(); ++it)
+ MatchChecksumDlg::checksumTypesFilter += ("*."+it.key()+" ");
+}
+
+// --------------------------------------------------
+
+// returns a list of tools which can work with recursive or non-recursive mode and are installed
+// note: only 1 tool from each type is suggested
+static TQPtrList<CS_Tool> getTools(bool folders) {
+ TQPtrList<CS_Tool> result;
+ uint i;
+ for (i=0; i < sizeof(cs_tools)/sizeof(CS_Tool); ++i) {
+ if (result.last() && result.last()->type == cs_tools[i].type) continue; // 1 from each type please
+ if (folders && !cs_tools[i].recursive) continue;
+ if (KrServices::cmdExist(cs_tools[i].binary))
+ result.append(&cs_tools[i]);
+ }
+
+ return result;
+}
+
+// ------------- CreateChecksumDlg
+
+CreateChecksumDlg::CreateChecksumDlg(const TQStringList& files, bool containFolders, const TQString& path):
+ KDialogBase(Plain, i18n("Create Checksum"), Ok | Cancel, Ok, krApp) {
+
+ TQPtrList<CS_Tool> tools = getTools(containFolders);
+
+ if (tools.count() == 0) { // nothing was suggested?!
+ TQString error = i18n("<qt>Can't calculate checksum since no supported tool was found. "
+ "Please check the <b>Dependencies</b> page in Krusader's settings.</qt>");
+ if (containFolders)
+ error += i18n("<qt><b>Note</b>: you've selected directories, and probably have no recursive checksum tool installed."
+ " Krusader currently supports <i>md5deep, sha1deep, sha256deep, tigerdeep and cfv</i></qt>");
+ KMessageBox::error(0, error);
+ return;
+ }
+
+ TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1,
+ KDialogBase::marginHint(), KDialogBase::spacingHint());
+
+ int row=0;
+
+ // title (icon+text)
+ TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel *p = new TQLabel(plainPage());
+ p->setPixmap(krLoader->loadIcon("application-octet-stream", TDEIcon::Desktop, 32));
+ hlayout->addWidget(p);
+ TQLabel *l1 = new TQLabel(i18n("About to calculate checksum for the following files") +
+ (containFolders ? i18n(" and folders:") : ":"), plainPage());
+ hlayout->addWidget(l1);
+ layout->addMultiCellLayout(hlayout, row, row, 0, 1, TQt::AlignLeft);
+ ++row;
+
+ // file list
+ TDEListBox *lb = new TDEListBox(plainPage());
+ lb->insertStringList(files);
+ layout->addMultiCellWidget(lb, row, row, 0, 1);
+ ++row;
+
+ // checksum method
+ TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel *l2 = new TQLabel(i18n("Select the checksum method:"), plainPage());
+ hlayout2->addWidget(l2);
+ KComboBox *method = new KComboBox(plainPage());
+ // -- fill the combo with available methods
+ uint i;
+ for ( i=0; i<tools.count(); ++i )
+ method->insertItem( cs_typeToText[tools.at(i)->type], i);
+ method->setFocus();
+ hlayout2->addWidget(method);
+ layout->addMultiCellLayout(hlayout2, row, row, 0, 1, TQt::AlignLeft);
+ ++row;
+
+ if (exec() != Accepted) return;
+ // else implied: run the process
+ tmpOut = new KTempFile(locateLocal("tmp", "krusader"), ".stdout" );
+ tmpErr = new KTempFile(locateLocal("tmp", "krusader"), ".stderr" );
+ TDEProcess proc;
+ CS_Tool *mytool = tools.at(method->currentItem());
+ mytool->create(proc, mytool, KrServices::quote(files), TQString(), containFolders,
+ tmpOut->name(), tmpErr->name(), method->currentText());
+
+ krApp->startWaiting(i18n("Calculating checksums ..."), 0, true);
+ TQApplication::setOverrideCursor( KCursor::waitCursor() );
+ bool r = proc.start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
+ if (r) while ( proc.isRunning() ) {
+ usleep( 500 );
+ tqApp->processEvents();
+ if (krApp->wasWaitingCancelled()) { // user cancelled
+ proc.kill();
+ TQApplication::restoreOverrideCursor();
+ return;
+ }
+ };
+ krApp->stopWait();
+ TQApplication::restoreOverrideCursor();
+ if (!r || !proc.normalExit()) {
+ KMessageBox::error(0, i18n("<qt>There was an error while running <b>%1</b>.</qt>").arg(mytool->binary));
+ return;
+ }
+
+ // suggest a filename
+ TQString suggestedFilename = path + '/';
+ if (files.count() > 1) suggestedFilename += ("checksum." + cs_typeToText[mytool->type]);
+ else suggestedFilename += (files[0] + '.' + cs_typeToText[mytool->type]);
+ // send both stdout and stderr
+ TQStringList stdOut, stdErr;
+ if (!KrServices::fileToStringList(tmpOut->textStream(), stdOut) ||
+ !KrServices::fileToStringList(tmpErr->textStream(), stdErr)) {
+ KMessageBox::error(krApp, i18n("Error reading stdout or stderr"));
+ return;
+ }
+
+ ChecksumResultsDlg dlg( stdOut, stdErr, suggestedFilename, mytool->binary, cs_typeToText[mytool->type], mytool->standardFormat);
+ tmpOut->unlink(); delete tmpOut;
+ tmpErr->unlink(); delete tmpErr;
+}
+
+// ------------- MatchChecksumDlg
+
+TQString MatchChecksumDlg::checksumTypesFilter;
+
+MatchChecksumDlg::MatchChecksumDlg(const TQStringList& files, bool containFolders,
+ const TQString& path, const TQString& checksumFile):
+ KDialogBase(Plain, i18n("Verify Checksum"), Ok | Cancel, Ok, krApp) {
+
+ TQPtrList<CS_Tool> tools = getTools(containFolders);
+
+ if (tools.count() == 0) { // nothing was suggested?!
+ TQString error = i18n("<qt>Can't verify checksum since no supported tool was found. "
+ "Please check the <b>Dependencies</b> page in Krusader's settings.</qt>");
+ if (containFolders)
+ error += i18n("<qt><b>Note</b>: you've selected directories, and probably have no recursive checksum tool installed."
+ " Krusader currently supports <i>md5deep, sha1deep, sha256deep, tigerdeep and cfv</i></qt>");
+ KMessageBox::error(0, error);
+ return;
+ }
+
+ TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1,
+ KDialogBase::marginHint(), KDialogBase::spacingHint());
+
+ int row=0;
+
+ // title (icon+text)
+ TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel *p = new TQLabel(plainPage());
+ p->setPixmap(krLoader->loadIcon("application-octet-stream", TDEIcon::Desktop, 32));
+ hlayout->addWidget(p);
+ TQLabel *l1 = new TQLabel(i18n("About to verify checksum for the following files") +
+ (containFolders ? i18n(" and folders:") : ":"), plainPage());
+ hlayout->addWidget(l1);
+ layout->addMultiCellLayout(hlayout, row, row, 0, 1, TQt::AlignLeft);
+ ++row;
+
+ // file list
+ TDEListBox *lb = new TDEListBox(plainPage());
+ lb->insertStringList(files);
+ layout->addMultiCellWidget(lb, row, row, 0, 1);
+ ++row;
+
+ // checksum file
+ TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel *l2 = new TQLabel(i18n("Checksum file:"), plainPage());
+ hlayout2->addWidget(l2);
+ KURLRequester *checksumFileReq = new KURLRequester( plainPage() );
+ if (!checksumFile.isEmpty())
+ checksumFileReq->setURL(checksumFile);
+ checksumFileReq->fileDialog()->setURL(path);
+ checksumFileReq->setFocus();
+ hlayout2->addWidget(checksumFileReq);
+ layout->addMultiCellLayout(hlayout2, row, row, 0, 1, TQt::AlignLeft);
+
+ if (exec() != Accepted) return;
+ TQString file = checksumFileReq->url();
+ TQString extension;
+ if (!verifyChecksumFile(file, extension)) {
+ KMessageBox::error(0, i18n("<qt>Error reading checksum file <i>%1</i>.<br />Please specify a valid checksum file.</qt>").arg(file));
+ return;
+ }
+
+ // do we have a tool for that extension?
+ uint i;
+ CS_Tool *mytool = 0;
+ for ( i=0; i < tools.count(); ++i )
+ if (cs_typeToText[tools.at(i)->type] == extension.lower()) {
+ mytool = tools.at(i);
+ break;
+ }
+ if (!mytool) {
+ KMessageBox::error(0, i18n("<qt>Krusader can't find a checksum tool that handles %1 on your system. Please check the <b>Dependencies</b> page in Krusader's settings.</qt>").arg(extension));
+ return;
+ }
+
+ // else implied: run the process
+ tmpOut = new KTempFile(locateLocal("tmp", "krusader"), ".stdout" );
+ tmpErr = new KTempFile(locateLocal("tmp", "krusader"), ".stderr" );
+ TDEProcess proc;
+ mytool->verify(proc, mytool, KrServices::quote(files), KrServices::quote(file), containFolders, tmpOut->name(), tmpErr->name(), extension);
+ krApp->startWaiting(i18n("Verifying checksums ..."), 0, true);
+ TQApplication::setOverrideCursor( KCursor::waitCursor() );
+ bool r = proc.start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
+ if (r) while ( proc.isRunning() ) {
+ usleep( 500 );
+ tqApp->processEvents();
+ if (krApp->wasWaitingCancelled()) { // user cancelled
+ proc.kill();
+ TQApplication::restoreOverrideCursor();
+ return;
+ }
+ };
+ if (!r || !proc.normalExit()) {
+ KMessageBox::error(0, i18n("<qt>There was an error while running <b>%1</b>.</qt>").arg(mytool->binary));
+ return;
+ }
+ TQApplication::restoreOverrideCursor();
+ krApp->stopWait();
+ // send both stdout and stderr
+ TQStringList stdOut,stdErr;
+ if (!KrServices::fileToStringList(tmpOut->textStream(), stdOut) ||
+ !KrServices::fileToStringList(tmpErr->textStream(), stdErr)) {
+ KMessageBox::error(krApp, i18n("Error reading stdout or stderr"));
+ return;
+ }
+ VerifyResultDlg dlg(mytool->failed(stdOut, stdErr));
+ tmpOut->unlink(); delete tmpOut;
+ tmpErr->unlink(); delete tmpErr;
+}
+
+bool MatchChecksumDlg::verifyChecksumFile(TQString path, TQString& extension) {
+ TQFileInfo f(path);
+ if (!f.exists() || f.isDir()) return false;
+ // find the extension
+ extension = path.mid(path.findRev(".")+1);
+
+ // TODO: do we know the extension? if not, ask the user for one
+
+
+ return true;
+}
+
+// ------------- VerifyResultDlg
+VerifyResultDlg::VerifyResultDlg(const TQStringList& failed):
+ KDialogBase(Plain, i18n("Verify Checksum"), Close, Close, krApp) {
+ TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1,
+ KDialogBase::marginHint(), KDialogBase::spacingHint());
+
+ bool errors = failed.size()>0;
+ int row = 0;
+
+ // create the icon and title
+ TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel p(plainPage());
+ p.setPixmap(krLoader->loadIcon(errors ? "messagebox_critical" : "messagebox_info", TDEIcon::Desktop, 32));
+ hlayout->addWidget(&p);
+
+ TQLabel *l1 = new TQLabel((errors ? i18n("Errors were detected while verifying the checksums") :
+ i18n("Checksums were verified successfully")), plainPage());
+ hlayout->addWidget(l1);
+ layout->addMultiCellLayout(hlayout,row,row,0,1, TQt::AlignLeft);
+ ++row;
+
+ if (errors) {
+ TQLabel *l3 = new TQLabel(i18n("The following files have failed:"), plainPage());
+ layout->addMultiCellWidget(l3, row, row, 0, 1);
+ ++row;
+ TDEListBox *lb2 = new TDEListBox(plainPage());
+ lb2->insertStringList(failed);
+ layout->addMultiCellWidget(lb2, row, row, 0, 1);
+ ++row;
+ }
+
+ exec();
+}
+
+// ------------- ChecksumResultsDlg
+
+ChecksumResultsDlg::ChecksumResultsDlg(const TQStringList& stdOut, const TQStringList& stdErr,
+ const TQString& suggestedFilename, const TQString& binary, const TQString& /* type */, bool standardFormat):
+ KDialogBase(Plain, i18n("Create Checksum"), Ok | Cancel, Ok, krApp), _binary(binary) {
+ TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1,
+ KDialogBase::marginHint(), KDialogBase::spacingHint());
+
+ // md5 tools display errors into stderr, so we'll use that to determine the result of the job
+ bool errors = stdErr.size()>0;
+ bool successes = stdOut.size()>0;
+ int row = 0;
+
+ // create the icon and title
+ TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ TQLabel p(plainPage());
+ p.setPixmap(krLoader->loadIcon(errors ? "messagebox_critical" : "messagebox_info", TDEIcon::Desktop, 32));
+ hlayout->addWidget(&p);
+
+ TQLabel *l1 = new TQLabel((errors ? i18n("Errors were detected while creating the checksums") :
+ i18n("Checksums were created successfully")), plainPage());
+ hlayout->addWidget(l1);
+ layout->addMultiCellLayout(hlayout,row,row,0,1, TQt::AlignLeft);
+ ++row;
+
+ if (successes) {
+ if (errors) {
+ TQLabel *l2 = new TQLabel(i18n("Here are the calculated checksums:"), plainPage());
+ layout->addMultiCellWidget(l2, row, row, 0, 1);
+ ++row;
+ }
+ TDEListView *lv = new TDEListView(plainPage());
+ if(standardFormat){
+ lv->addColumn(i18n("Hash"));
+ lv->addColumn(i18n("File"));
+ lv->setAllColumnsShowFocus(true);
+ } else {
+ lv->addColumn(i18n("File and hash"));
+ }
+ for ( TQStringList::ConstIterator it = stdOut.begin(); it != stdOut.end(); ++it ) {
+ TQString line = (*it);
+ if(standardFormat) {
+ int space = line.find(' ');
+ new TDEListViewItem(lv, line.left(space), line.mid(space+2));
+ } else {
+ new TDEListViewItem(lv, line);
+ }
+ }
+ layout->addMultiCellWidget(lv, row, row, 0, 1);
+ ++row;
+ }
+
+ if (errors) {
+ TQFrame *line1 = new TQFrame( plainPage() );
+ line1->setGeometry( TQRect( 60, 210, 501, 20 ) );
+ line1->setFrameShape( TQFrame::HLine );
+ line1->setFrameShadow( TQFrame::Sunken );
+ layout->addMultiCellWidget(line1, row, row, 0, 1);
+ ++row;
+
+ TQLabel *l3 = new TQLabel(i18n("Here are the errors received:"), plainPage());
+ layout->addMultiCellWidget(l3, row, row, 0, 1);
+ ++row;
+ TDEListBox *lb = new TDEListBox(plainPage());
+ lb->insertStringList(stdErr);
+ layout->addMultiCellWidget(lb, row, row, 0, 1);
+ ++row;
+ }
+
+ // save checksum to disk, if any hashes are found
+ KURLRequester *checksumFile=0;
+ TQCheckBox *saveFileCb=0;
+ if (successes) {
+ TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint());
+ saveFileCb = new TQCheckBox(i18n("Save checksum to file:"), plainPage());
+ saveFileCb->setChecked(true);
+ hlayout2->addWidget(saveFileCb);
+
+ checksumFile = new KURLRequester( suggestedFilename, plainPage() );
+ hlayout2->addWidget(checksumFile, TQt::AlignLeft);
+ layout->addMultiCellLayout(hlayout2, row, row,0,1, TQt::AlignLeft);
+ ++row;
+ connect(saveFileCb, TQ_SIGNAL(toggled(bool)), checksumFile, TQ_SLOT(setEnabled(bool)));
+ checksumFile->setFocus();
+ }
+
+ TQCheckBox *onePerFile=0;
+ if (stdOut.size() > 1 && standardFormat) {
+ onePerFile = new TQCheckBox(i18n("Checksum file for each source file"), plainPage());
+ onePerFile->setChecked(false);
+ // clicking this, disables the 'save as' part
+ connect(onePerFile, TQ_SIGNAL(toggled(bool)), saveFileCb, TQ_SLOT(toggle()));
+ connect(onePerFile, TQ_SIGNAL(toggled(bool)), saveFileCb, TQ_SLOT(setDisabled(bool)));
+ connect(onePerFile, TQ_SIGNAL(toggled(bool)), checksumFile, TQ_SLOT(setDisabled(bool)));
+ layout->addMultiCellWidget(onePerFile, row, row,0,1, TQt::AlignLeft);
+ ++row;
+ }
+
+ if (exec() == Accepted && successes) {
+ if (stdOut.size()>1 && standardFormat && onePerFile->isChecked()) {
+ savePerFile(stdOut, suggestedFilename.mid(suggestedFilename.findRev('.')));
+ } else if (saveFileCb->isEnabled() && saveFileCb->isChecked() && !checksumFile->url().simplifyWhiteSpace().isEmpty()) {
+ saveChecksum(stdOut, checksumFile->url());
+ }
+ }
+}
+
+bool ChecksumResultsDlg::saveChecksum(const TQStringList& data, TQString filename) {
+ if (TQFile::exists(filename) &&
+ KMessageBox::warningContinueCancel(this,
+ i18n("File %1 already exists.\nAre you sure you want to overwrite it?").arg(filename),
+ i18n("Warning"), i18n("Overwrite")) != KMessageBox::Continue) {
+ // find a better name to save to
+ filename = KFileDialog::getSaveFileName(TQString(), "*", 0, i18n("Select a file to save to"));
+ if (filename.simplifyWhiteSpace().isEmpty()) return false;
+ }
+ TQFile file(filename);
+ if (!file.open(IO_WriteOnly)) {
+ KMessageBox::detailedError(0, i18n("Error saving file %1").arg(filename),
+ file.errorString());
+ return false;
+ }
+ TQTextStream stream(&file);
+ for ( TQStringList::ConstIterator it = data.constBegin(); it != data.constEnd(); ++it)
+ stream << *it << "\n";
+ file.close();
+ return true;
+}
+
+void ChecksumResultsDlg::savePerFile(const TQStringList& data, const TQString& type) {
+ krApp->startWaiting(i18n("Saving checksum files..."), 0);
+ for ( TQStringList::ConstIterator it = data.begin(); it != data.end(); ++it ) {
+ TQString line = (*it);
+ TQString filename = line.mid(line.find(' ')+2)+type;
+ if (!saveChecksum(*it, filename)) {
+ KMessageBox::error(0, i18n("Errors occured while saving multiple checksums. Stopping"));
+ krApp->stopWait();
+ return;
+ }
+ }
+ krApp->stopWait();
+}