Reading multiple files from FileChooserDialog GTK 3 - c++

I am trying to open a Gtkmm::FileChooserDialog to choose multiple files and print their paths along with filenames to a label. I can open the dialog and choose the files but I am having a hard time reading the filenames to my variables.
FileChooserDialog openFileDialog("", FILE_CHOOSER_ACTION_OPEN);
openFileDialog.add_button("Cancel", RESPONSE_CANCEL);
openFileDialog.add_button("Open", RESPONSE_OK);
openFileDialog.set_current_folder(ustring::compose("%1/Desktop", ustring(getenv("HOME"))));
openFileDialog.set_transient_for(*this);
openFileDialog.set_select_multiple(true);
Glib::RefPtr<Gtk::FileFilter> fileFilter = Gtk::FileFilter::create();
fileFilter->set_name("Text Files (*.txt)");
fileFilter->add_pattern("*.txt");
openFileDialog.add_filter(fileFilter);
fileFilter = Gtk::FileFilter::create();
fileFilter->set_name("All Files (*.*)");
fileFilter->add_pattern("*.*");
openFileDialog.add_filter(fileFilter);
if (openFileDialog.run() == RESPONSE_OK)
label.set_text(ustring::compose("File = %1", ustring(openFileDialog.get_filename())));
return true;

You can use Gtk::FileChooser::get_filenames (Gtkmm 3.24):
if (openFileDialog.run() == Gtk::RESPONSE_OK)
{
for(const auto& fileName : openFileDialog.get_filenames())
{
label.set_text(Glib::ustring::compose("File = %1", Glib::ustring(fileName)));
}
}
which returns a std::vector of file names.
Note: In my answer, I keep overwriting the label variable because it was all the context there was in your code snippet. My be you have multiple labels or you want to pack all the file names somehow in a single label. I let this part to you.

Related

Append files to an existing zip file with Poco::Zip

After successfully compress the folder, here is my situation :
If append = true and overWrite = false I have to check whether if the target zip file exists or not if existed I will check the existed zip file which files it doesn't contain and append new file from the source folder to it.
My question is:
How can I open the zip file and put it to the compress object? or which others library in Poco should I use to open zip stream? I'm trying to use std::ifstream but Poco::zip::Compress doesn't seem to receive an std::ifstream
I surely have to modify the Poco source code itself to match with my requirement. Thanks in advance.
void ZipFile(string source, string target, List extensions, bool append, bool overWrite)
{
Poco::File tempFile(source);
if (tempFile.exists())
{
if (Poco::File(target).exists() && append && !overWrite) {
fs::path targetPath = fs::path(target);
std::ifstream targetFileStream(targetPath.string(), std::ios::binary);
std::ofstream outStream(target, ios::binary);
CompressEx compress(outStream, false, false);
if (tempFile.isDirectory())
{
Poco::Path sourceDir(source);
sourceDir.makeDirectory();
compress.addRecursive(sourceDir, Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL, false);
}
else if (tempFile.isFile())
{
Poco::Path path(tempFile.path());
compress.addFile(path, path.getFileName(), Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL);
}
compress.close(); // MUST be done to finalize the Zip file
outStream.close();
}
}
No need to modify the Poco source code. Poco allows you to get the contents of an archive and add files to it.
First, open the target archive to check which files are already in there:
Poco::ZipArchive archive(targetFileStream);
Then collect all files you want to add, that are not in the archive, yet:
std::vector<fs::path> files;
if (fs::is_directory(source)) {
for(auto &entry : fs::recursive_directory_iterator())
// if entry is file and not in zip
if (fs::is_regular_file(entry)
&& archive.findHeader(fs::relative(entry.path, source)) == archive.headerEnd()) {
files.push_back(entry.path);
}
} else if (fs::is_regular_file(entry)
&& archive.findHeader(source) == archive.headerEnd()) {
files.push_back(source);
}
Finally, add the files to your zip
Poco::Zip::ZipManipulator manipulator(target, false);
for(auto &file : files)
manipulator.addFile(fs::relative(file, source), file,
Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL);
I had no opportunity to test this. So try it out and see what needs to be done to make it work.

How to split a list into multiple lists based on elements?

I have a file which has multiple file in it. Multiple files have excel files. I could put them on a list
excel_files = []
for path, dirs, files in os.walk(bugra_path):
for filename in files:
if filename == 'desktop.ini': continue
excel_files.append(filename)
The output is like that:
['2019-11-kudup.xlsx', '2019-12-kudup.xlsx', '2019-11-kur.xlsx', '2019-12-kur.xlsx', '2019-11-bilateral_buys.xlsx', '2019-12-bilateral_buys.xlsx', '2019-11-bilateral_sells.xlsx', '2019-12-bilateral_sells.xlsx', '2019-11-dam_buys.xlsx', '2019-12-dam_buys.xlsx', '2019-11-dam_sells.xlsx', '2019-12-dam_sells.xlsx', '2019-11-productions.xlsx', '2019-12-productions.xlsx', '2019-11-ptf_smf.xlsx', '2019-12-ptf_smf.xlsx']
However, this not enough for me, I want to split this list into multiple lists based on its element names. I mean want to achieve this:
kudup_list = ['2019-11-kudup.xlsx', '2019-12-kudup.xlsx']
kur_list = ['2019-11-kur.xlsx', '2019-12-kur.xlsx']
bilateral_buys_list = ['2019-11-bilateral_buys.xlsx', '2019-12-bilateral_buys.xlsx']
bilateral_sells_list = ['2019-11-bilateral_sells.xlsx', '2019-12-bilateral_sells.xlsx']
dam_buys_list = ['2019-11-dam_buys.xlsx', '2019-12-dam_buys.xlsx']
dam_sells_list = ['2019-11-dam_sells.xlsx', '2019-12-dam_sells.xlsx']
productions_list = ['2019-11-productions.xlsx', '2019-12-productions.xlsx']
ptf_smf_list = ['2019-11-ptf_smf.xlsx', '2019-12-ptf_smf.xlsx']
How can I get this output?

Add unique suffix to file name

Sometimes I need to ensure I'm not overwriting an existing file when saving some data, and I'd like to use a function that appends a suffix similar to how a browser does it - if dir/file.txt exists, it becomes dir/file (1).txt.
This is an implementation I've made, that uses Qt functions:
// Adds a unique suffix to a file name so no existing file has the same file
// name. Can be used to avoid overwriting existing files. Works for both
// files/directories, and both relative/absolute paths. The suffix is in the
// form - "path/to/file.tar.gz", "path/to/file (1).tar.gz",
// "path/to/file (2).tar.gz", etc.
QString addUniqueSuffix(const QString &fileName)
{
// If the file doesn't exist return the same name.
if (!QFile::exists(fileName)) {
return fileName;
}
QFileInfo fileInfo(fileName);
QString ret;
// Split the file into 2 parts - dot+extension, and everything else. For
// example, "path/file.tar.gz" becomes "path/file"+".tar.gz", while
// "path/file" (note lack of extension) becomes "path/file"+"".
QString secondPart = fileInfo.completeSuffix();
QString firstPart;
if (!secondPart.isEmpty()) {
secondPart = "." + secondPart;
firstPart = fileName.left(fileName.size() - secondPart.size());
} else {
firstPart = fileName;
}
// Try with an ever-increasing number suffix, until we've reached a file
// that does not yet exist.
for (int ii = 1; ; ii++) {
// Construct the new file name by adding the unique number between the
// first and second part.
ret = QString("%1 (%2)%3").arg(firstPart).arg(ii).arg(secondPart);
// If no file exists with the new name, return it.
if (!QFile::exists(ret)) {
return ret;
}
}
}
QTemporaryFile can do it for non-temporary files, despite its name:
QTemporaryFile file("./foobarXXXXXX.txt");
file.open();
// now the file should have been renamed to something like ./foobarQSlkDJ.txt
file.setAutoRemove(false);
// now the file will not be removed when QTemporaryFile is deleted
A better solution is to use GUID
Or you can generate a hash based on bytes collected from within a file, either randomly or based on some data property that is fairly unique from file to file.

SharpLibZip: Add file without path

I'm using the following code, using the SharpZipLib library, to add files to a .zip file, but each file is being stored with its full path. I need to only store the file, in the 'root' of the .zip file.
string[] files = Directory.GetFiles(folderPath);
using (ZipFile zipFile = ZipFile.Create(zipFilePath))
{
zipFile.BeginUpdate();
foreach (string file in files)
{
zipFile.Add(file);
}
zipFile.CommitUpdate();
}
I can't find anything about an option for this in the supplied documentation. As this is a very popular library, I hope someone reading this may know something.
My solution was to set the NameTransform object property of the ZipFile to a ZipNameTransform with its TrimPrefix set to the directory of the file. This causes the directory part of the entry names, which are full file paths, to be removed.
public static void ZipFolderContents(string folderPath, string zipFilePath)
{
string[] files = Directory.GetFiles(folderPath);
using (ZipFile zipFile = ZipFile.Create(zipFilePath))
{
zipFile.NameTransform = new ZipNameTransform(folderPath);
foreach (string file in files)
{
zipFile.BeginUpdate();
zipFile.Add(file);
zipFile.CommitUpdate();
}
}
}
What's cool is the the NameTransform property is of type INameTransform, allowing customisation of the name transforms.
How about using System.IO.Path.GetFileName() combined with the entryName parameter of ZipFile.Add()?
string[] files = Directory.GetFiles(folderPath);
using (ZipFile zipFile = ZipFile.Create(zipFilePath))
{
zipFile.BeginUpdate();
foreach (string file in files)
{
zipFile.Add(file, System.IO.Path.GetFileName(file));
}
zipFile.CommitUpdate();
}
The MSDN entry for Directory.GetFiles() states that The returned file names are appended to the supplied path parameter. (http://msdn.microsoft.com/en-us/library/07wt70x2.aspx), so the strings you are passing to zipFile.Add() contain the path.
According to the SharpZipLib documentation, there is an overload of the Add method,
public void Add(string fileName, string entryName)
Parameters:
fileName(String) The name of the file to add.
entryName (String) The name to use for the ZipEntry on the Zip file created.
Try this approach:
string[] files = Directory.GetFiles(folderPath);
using (ZipFile zipFile = ZipFile.Create(zipFilePath))
{
zipFile.BeginUpdate();
foreach (string file in files)
{
zipFile.Add(file, Path.GetFileName(file));
}
zipFile.CommitUpdate();
}

Populating a database with file names from directories

I have an application which behaves as a slideshow for all pictures in a folder. It is written in Borland's C++ Builder (9). It currently uses some borrowed code to throw the filenames into a listbox and save the listbox items as a text file.
I want to update this so that the filenames are stored in a proper database so that I can include extra fields and do proper SQL things with it.
So basically I would be able to work it out if I saw some 'sample' code doing the same thing.
So if anyone knows of any code that does this I would be greatful. It needs to be able to do it on certain file types... not just all the files.
You basically neeed to write a recursive function with a TDataSet parameter.
(I could not compile my code, so you get it "as is")
void AddFiles(AnsiString path, TDataSet *DataSet)
{
TSearchRec sr;
int f;
f = FindFirst(path+"\\*.*", faAnyFile, sr);
while( !f )
{
if(sr.Attr & faDirectory)
{
if(sr.Name != "." && sr.Name != "..")
{
path.sprintf("%s%s%s", path, "\\", sr.Name);
AddFiles(path, DataSet);
}
}
else
{
DataSet->Append();
DataSet->FieldByName("Name")->Value = sr.Name;
/* other fields ... */
DataSet->Post();
}
f = FindNext(sr);
}
FindClose(sr);
}