how to determine if the mount successful in QT code - qt

I have this function on mounting a smb:// connection. What if there is an error that is not in my condition. Is there a better way to determine if the mount is sucessful or not? Im using ubuntu 11.04 and qt 4.7.3
bool mwDM::mountFolder()
{
QString smbUsername,smbPassword,serverPath,mountPath;
QProcess connectSamba;
QString terminalCommand,linuxPassword;
QDir dir("/mnt/backup");
smbUsername=ReadINIStr(iniPath,"Server","Username","");
smbPassword=ReadINIStr(iniPath,"Server","Password","");
serverPath=ReadINIStr(iniPath,"Server","Hostname","");
serverPath="//" + serverPath;
mountPath="/mnt/backup";
linuxPassword=ReadINIStr(iniPath,"Server","AdminPassword","");
terminalCommand="echo "+linuxPassword+" | sudo -S mount -t cifs -o username="+smbUsername+",password="+smbPassword+" "+serverPath+ " "+mountPath;
connectSamba.start("sh",QStringList() << "-c" << terminalCommand );
if(!connectSamba.waitForStarted())
{
LogWrite("Failed to start mount command", Qt::red);
}
if(!connectSamba.waitForFinished() )
{
LogWrite("Failed to finish mount command", Qt::red);
}
QString connectSamba_stderr = connectSamba.readAllStandardError();
qDebug() << "connectSamba_stderr" << connectSamba_stderr;
if(connectSamba_stderr.contains("is not a valid block device"))
{
LogWrite("Hostname is invalid", Qt::red);
return false;
}
else if(connectSamba_stderr.contains("3 incorrect password attempts"))
{
LogWrite("Admin password is incorrect", Qt::red);
return false;
}
else if(connectSamba_stderr.contains("wrong fs type, bad option, bad superblock on"))
{
LogWrite("Hostname is invalid", Qt::red);
return false;
}
else if(connectSamba_stderr.contains("Invalid argument"))
{
LogWrite("Mount error(22): Invalid argument", Qt::red);
return false;
}
else if(!dir.exists())
{
LogWrite("Directory doesn't exists", Qt::red);
return false;
}
else
{
return true;
}
}

You can check last error of a QProcess by using error and state functions (Documentation for "error" Documentation for "state").
"What if there is an error that is not in my condition."
You can add something like this in your code:
else if(connectSamba.state() == QProcess::NotRunning && connectSamba.error() >= 0)
{
LogWrite("Unknown error", Qt::red);
return false;
}
Or, if you want to give more specific information, you can create a condition for each error code separately. Here's a list of codes.
Alternatively, don't add the above block to the error checking code. Instead, create a slot to which you connect the error signal of connectSamba class:
// add this line below "QProcess connectSamba;" line in mwDm::mountFolder
connect(&connectSamba, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError));
// after that, use your original error checking code in mountFolder
// slot code
void mwDm::onError(QProcess::ProcessError)
{
//use switch-case or if to check type of error if you want
processErrorOccurred = true; // processErrorOccurred is a member of mwDm
}

Related

How to properly disconnect signal ready read from QNetworkreply

following issue abot my code. For unserstanding reason I connect to an event stream which publish every minute the actual status of a device under the url of : "urldevice"/event-stream. I connect a slot to the signal "readyread" and will disconnect. But still I am calling the disconnect function I recieve information in the cnnected slot.
Here is my code
QNetworkRequest request(_url + "events");
request.setRawHeader("Accept", "text/event-stream");
request.setHeader(QNetworkRequest::UserAgentHeader, "Plugin");
if (_token != "") {
request.setRawHeader("accept", "*/*");
QString token = "Bearer " + _token;
request.setRawHeader("Authorization", token.toUtf8());
}
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached
_sseReply = _sseNetworkManager->get(request);
QObject::connect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
void streamReceived() {
if (_sseReply->error() == QNetworkReply::NoError) {
qCDebug(m_logCategory) << "streamrecieved";
} else {
qCDebug(m_logCategory) << "disconnect";
}
}
void disconnect() {
if (_sseReply->isRunning()) {
_sseReply->abort();
_sseReply->close();
_sseNetworkManager->disconnect(_sseReply,&QNetworkReply::readyRead,this,&streamReceived);
_sseNetworkManager->disconnect();
_sseReply->disconnect();
qCDebug(m_logCategory) << "isrunnung";
}
_flagStandby = true;
QObject::disconnect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
}
after caling disconnect() I see all the time
disconnect
in my log
How do I properly disconnect from the signal???

How do I know whether FileInputStream opens a file?

I am using Poco::FileInputStream to design a copy function
void do_copy_file(Poco::FileInputStream & iss)
{
Poco::FileOutputStream fos("output.txt");
Poco::StreamCopier::copyStream(iss, fos);
}
Then, a user can call do_copy_file like this
Poco::FileInputStream fis;
do_copy_file(fis);
My question: Can I judge whether iss refers a valid file?
The Poco::FileOutputStream just throws a Poco::FileException if an error occurs when trying to open it, e.g. if a invalid file path is used. It doesn't have any function to test whether it is valid.
What you could do is change your do_copy_file() function to catch an Poco::FileException exception and return a boolean value - true if opened successfully or false otherwise:
bool do_copy_file(Poco::FileInputStream & iss)
{
bool result(true);
try
{
Poco::FileOutputStream fos("output.txt");
Poco::StreamCopier::copyStream(iss, fos);
}
catch (const Poco::FileException&)
{
result = false;
}
return result;
}
Then you call it like this:
Poco::FileInputStream fis;
if (do_copy_file(fis)
{
//output file stream opened successfully
}
If you want do_copy_file() to catch an exception for opening the input stream I would recommend doing that in the function itself. Instead of passing the input streams pass the file paths instead:
bool do_copy_file(const std::string &inputFile, const std::string& outputFile)
{
bool result(true);
try
{
Poco::FileInputStream fis(inputFile);
Poco::FileOutputStream fos(outputFile);
Poco::StreamCopier::copyStream(fis, fos);
}
catch (const Poco::FileException&)
{
result = false;
}
return result;
}

Qt need help to disable scroll on combobox

Hello I need help to turn off scrool on combobox , I have written some code but I get error, can someone help me
list << ui->comboBox << ui->comboBox_2 << ui->comboBox_3;
for(i =0 ; i<list.count();i++)
{
list[i]->installEventFilter(this);
list[i]->setFocusPolicy(Qt::StrongFocus);
}
bool MainWindow::eventFilter(QObject * o,QEvent * e)
{
if(e->type() == QEvent::Wheel && o == list.at(i) )
{
return true;
}
return false;
}
When i run program i get this Error
ASSERT failure in QList::at: "index out of range"
start in debug mode see where is the error.
solution: remove o == list.at(i)

Setting default TWAIN data source without using API UI menu

Using the twaindotnet library in C#, I'm wondering if there's a way to set the default datasource using the library.
As a feeble attempt, I've tried adding a SetDefault method to the DataSource class of twaindonet, like this
public static void SetDefault(Identity applicationId, IWindowsMessageHook messageHook, DataSource newDataSource)
{
var defaultSourceId = newDataSource.SourceId;
// Attempt to get information about the system default source
var result = Twain32Native.DsmIdentity(
applicationId,
IntPtr.Zero,
DataGroup.Control,
DataArgumentType.Identity,
Message.Set,
defaultSourceId);
if (result != TwainResult.Success)
{
var status = DataSourceManager.GetConditionCode(applicationId, null);
throw new TwainException("Error getting information about the default source: " + result, result, status);
}
}
which is called from the DataSourceManage class like this
public void SelectSource(DataSource dataSource)
{
DataSource.Dispose();
DataSource.SetDefault(ApplicationId, _messageHook, dataSource);
}
But when I try to use SetDefault, Twain32Native.DsmIdentity always results in Failure being returned.
I basically copied from SetDefault the setDefaultDataSource method from TWAIN sample Data Source and Application
pTW_IDENTITY TwainApp::setDefaultDataSource(unsigned int _index)
{
if(m_DSMState < 3)
{
cout << "You need to open the DSM first." << endl;
return NULL;
}
else if(m_DSMState > 3)
{
PrintCMDMessage("A source has already been opened, please close it first\n");
return NULL;
}
if(_index >= 0 && _index < m_DataSources.size())
{
m_pDataSource = &(m_DataSources[_index]);
// set the specific data source
TW_UINT16 twrc;
twrc = _DSM_Entry(
&m_MyInfo,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_SET,
(TW_MEMREF) m_pDataSource);
switch (twrc)
{
case TWRC_SUCCESS:
break;
case TWRC_FAILURE:
printError(0, "Failed to get the data source info!");
break;
}
}
else
{
return NULL;
}
return m_pDataSource;
}
Any help would be greatly appreciated.
The possible cause is that the version of your TWAIN DSM is too low. Only DSM 2.0 or above supports setting default TWAIN data source.

Copy directory using Qt

I want to copy a directory from one drive to another drive. My selected directory contains many sub directories and files.
How can I implement the same using Qt?
void copyPath(QString src, QString dst)
{
QDir dir(src);
if (! dir.exists())
return;
foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
QString dst_path = dst + QDir::separator() + d;
dir.mkpath(dst_path);
copyPath(src+ QDir::separator() + d, dst_path);
}
foreach (QString f, dir.entryList(QDir::Files)) {
QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f);
}
}
Manually, you can do the next things:
1). with func below you generate folders/files list (recursively) - the destination files.
static void recurseAddDir(QDir d, QStringList & list) {
QStringList qsl = d.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
foreach (QString file, qsl) {
QFileInfo finfo(QString("%1/%2").arg(d.path()).arg(file));
if (finfo.isSymLink())
return;
if (finfo.isDir()) {
QString dirname = finfo.fileName();
QDir sd(finfo.filePath());
recurseAddDir(sd, list);
} else
list << QDir::toNativeSeparators(finfo.filePath());
}
}
2). then you may to start copying files from destination list to the new source directory like that:
for (int i = 0; i < gtdStringList.count(); i++) {
progressDialog.setValue(i);
progressDialog.setLabelText(tr("%1 Coping file number %2 of %3 ")
.arg((conf->isConsole) ? tr("Making copy of the Alta-GTD\n") : "")
.arg(i + 1)
.arg(gtdStringList.count()));
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
if (progressDialog.wasCanceled()) {
// removing tmp files/folders
rmDirectoryRecursive(tmpFolder);
rmDirectoryRecursive(tmpFolderPlus);
setEnableGUI(true);
return;
}
// coping
if (!QFile::copy(gtdStringList.at(i), tmpStringList.at(i))) {
if (warningFlag) {
QMessageBox box(this);
QString name = tr("Question");
QString file1 = getShortName(gtdStringList.at(i), QString("\\...\\"));
QString file2 = getShortName(tmpStringList.at(i), QString("\\...\\"));
QString text = tr("Cannot copy <b>%1</b> <p>to <b>%2</b>" \
"<p>This file will be ignored, just press <b>Yes</b> button" \
"<p>Press <b>YesToAll</b> button to ignore other warnings automatically..." \
"<p>Or press <b>Abort</b> to cancel operation").arg(file1).arg(file2);
box.setModal(true);
box.setWindowTitle(name);
box.setText(QString::fromLatin1("%1").arg(text));
box.setIcon(QMessageBox::Question);
box.setStandardButtons(QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::Abort);
switch (box.exec()) {
case (QMessageBox::YesToAll):
warningFlag = false;
break;
case (QMessageBox::Yes):
break;
case (QMessageBox::Abort):
rmDirectoryRecursive(tmpFolder);
rmDirectoryRecursive(tmpFolderPlus);
setEnableGUI(true);
return;
}
}
}
}
And that's all. Good luck!
I wanted something similar, and was googling (in vain), so this is where I've got to:
static bool cpDir(const QString &srcPath, const QString &dstPath)
{
rmDir(dstPath);
QDir parentDstDir(QFileInfo(dstPath).path());
if (!parentDstDir.mkdir(QFileInfo(dstPath).fileName()))
return false;
QDir srcDir(srcPath);
foreach(const QFileInfo &info, srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
QString srcItemPath = srcPath + "/" + info.fileName();
QString dstItemPath = dstPath + "/" + info.fileName();
if (info.isDir()) {
if (!cpDir(srcItemPath, dstItemPath)) {
return false;
}
} else if (info.isFile()) {
if (!QFile::copy(srcItemPath, dstItemPath)) {
return false;
}
} else {
qDebug() << "Unhandled item" << info.filePath() << "in cpDir";
}
}
return true;
}
It uses an rmDir function that looks pretty similar:
static bool rmDir(const QString &dirPath)
{
QDir dir(dirPath);
if (!dir.exists())
return true;
foreach(const QFileInfo &info, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
if (info.isDir()) {
if (!rmDir(info.filePath()))
return false;
} else {
if (!dir.remove(info.fileName()))
return false;
}
}
QDir parentDir(QFileInfo(dirPath).path());
return parentDir.rmdir(QFileInfo(dirPath).fileName());
}
This doesn't handle links and special files, btw.
The hard way. Copy every file individually.
Use QDir::entryList() to iterate over the content of a directory
Use QDir::cd() and QDir::cdUp() to go in and out of directories
Use QDir::mkdir() and QDir::mkpath() to create the new folders tree
and finally, use QFile::copy() to copy the actual files
This is basically petch's answer with a slight change due to it breaking for me in Qt 5.6 (this is the top question hit), so all credit goes to petch.
function
bool copyPath(QString sourceDir, QString destinationDir, bool overWriteDirectory)
{
QDir originDirectory(sourceDir);
if (! originDirectory.exists())
{
return false;
}
QDir destinationDirectory(destinationDir);
if(destinationDirectory.exists() && !overWriteDirectory)
{
return false;
}
else if(destinationDirectory.exists() && overWriteDirectory)
{
destinationDirectory.removeRecursively();
}
originDirectory.mkpath(destinationDir);
foreach (QString directoryName, originDirectory.entryList(QDir::Dirs | \
QDir::NoDotAndDotDot))
{
QString destinationPath = destinationDir + "/" + directoryName;
originDirectory.mkpath(destinationPath);
copyPath(sourceDir + "/" + directoryName, destinationPath, overWriteDirectory);
}
foreach (QString fileName, originDirectory.entryList(QDir::Files))
{
QFile::copy(sourceDir + "/" + fileName, destinationDir + "/" + fileName);
}
/*! Possible race-condition mitigation? */
QDir finalDestination(destinationDir);
finalDestination.refresh();
if(finalDestination.exists())
{
return true;
}
return false;
}
Use:
/*! Overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, true);
/*! Do not overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, false);
Try this:
bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
QDir sourceDir(fromDir);
QDir targetDir(toDir);
if(!targetDir.exists()){ /* if directory don't exists, build it */
if(!targetDir.mkdir(targetDir.absolutePath()))
return false;
}
QFileInfoList fileInfoList = sourceDir.entryInfoList();
foreach(QFileInfo fileInfo, fileInfoList){
if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
continue;
if(fileInfo.isDir()){ /* if it is directory, copy recursively*/
if(!copyDirectoryFiles(fileInfo.filePath(),
targetDir.filePath(fileInfo.fileName()),
coverFileIfExist))
return false;
}
else{ /* if coverFileIfExist == true, remove old file first */
if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
targetDir.remove(fileInfo.fileName());
}
// files copy
if(!QFile::copy(fileInfo.filePath(),
targetDir.filePath(fileInfo.fileName()))){
return false;
}
}
}
return true;
}
I have made a library to manipulate files by a shell command style API. It supports a recursively copy of files and handled several more conditions.
https://github.com/benlau/qtshell#cp
Example
cp("-a", ":/*", "/target"); // copy all files from qrc resource to target path recursively
cp("tmp.txt", "/tmp");
cp("*.txt", "/tmp");
cp("/tmp/123.txt", "456.txt");
cp("-va","src/*", "/tmp");
cp("-a", ":resource","/target");
Since I had some trouble with App-Bundles on macOS, here's a solution with QDirIterator
void copyAndReplaceFolderContents(const QString &fromDir, const QString &toDir, bool copyAndRemove = false) {
QDirIterator it(fromDir, QDirIterator::Subdirectories);
QDir dir(fromDir);
const int absSourcePathLength = dir.absoluteFilePath(fromDir).length();
while (it.hasNext()){
it.next();
const auto fileInfo = it.fileInfo();
if(!fileInfo.isHidden()) { //filters dot and dotdot
const QString subPathStructure = fileInfo.absoluteFilePath().mid(absSourcePathLength);
const QString constructedAbsolutePath = toDir + subPathStructure;
if(fileInfo.isDir()){
//Create directory in target folder
dir.mkpath(constructedAbsolutePath);
} else if(fileInfo.isFile()) {
//Copy File to target directory
//Remove file at target location, if it exists. Otherwise QFile::copy will fail
QFile::remove(constructedAbsolutePath);
QFile::copy(fileInfo.absoluteFilePath(), constructedAbsolutePath);
}
}
}
if(copyAndRemove)
dir.removeRecursively();
}
If you are on a linux based system and the cp command exists and can be run, then you can use a QProcess to launch a bash:
auto copy = new QProcess(this);
copy->start(QStringLiteral("cp -rv %1 %2").arg(sourceFolder, destinationFolder));
copy->waitForFinished();
copy->close();
cp details:
-r means recursively
-v means it prints the successfully copied file
Note: if the copy operation is long, then you need to managed the UI freezing, as noted here
Assuming the target location is empty "no existing files or folders
with the same names" and you have no problem to use a Recursive
function!! to copy a directory recursively then the code will be something like this
void copy_all(QString dst_loc, QString src_loc)
{
QDir src(src_loc);
for(QFileInfo file_info : src.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)){
if(file_info.isDir()){
src.mkpath(dst_loc+'/'+file_info.fileName());
copy_all(dst_loc+'/'+file_info.fileName(),file_info.absoluteFilePath());
}
QFile::copy(file_info.absoluteFilePath(), dst_loc+'/'+file_info.fileName());
}
}
if you ever dealt with tree data structures and tried to create a Recursive function to do a "depth-first search" Alogorithm you will get a 85% similar algorithm, which Actually I got this idea from.
The second way, is by using a map data structure to hold the current
fileInfoList in a directory, and the corresponding state to show if
you have used this fileInfo or not yet. and you gather all
information firstly about sub directories and files from the source location.
And this is how most OS and other file managers do to copy data, by showing you the size of files to be copied, how many files and folders are going to be copied, and finally, if there is any conflict of files or folders with the same name before you even initiate copying "if you will do the same algorithm with the destination so that you can match filenames".
Good luck!.

Resources