<commit_before>/*-----------------------------------------------------------------------------
 This source file is part of Hopsan NG

 Copyright (c) 2011
    <NAME>, <NAME>, <NAME>, <NAME>,
    <NAME>, <NAME>, <NAME>, <NAME>

 This file is provided "as is", with no guarantee or warranty for the
 functionality or reliability of the contents. All contents in this file is
 the original work of the copyright holders at the Division of Fluid and
 Mechatronic Systems (Flumes) at Linköping University. Modifying, using or
 redistributing any part of this file is prohibited without explicit
 permission from the copyright holders.
-----------------------------------------------------------------------------*/

//!
//! @file   DesktopHandler.cpp
//! @author <NAME> <<EMAIL>>
//! @date   2013-03-13
//!
//! @brief Contains a utility class for handling desktop interaction, especially paths
//!
//$Id$

#include "DesktopHandler.h"
#include "common.h"

#include <QDesktopServices>
#include <QString>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QApplication>
#include "Utilities/GUIUtilities.h"

#if QT_VERSION >= 0x050000
#include <QStandardPaths>
QString getStandardLocation(QStandardPaths::StandardLocation type)
{
    QString location;
    QStringList locations = QStandardPaths::standardLocations(type);
    if (!locations.isEmpty())
    {
        // Take first reported location
        location = locations.first();
        // Append '/' to end if not already present
        if (location[location.size()-1] != '/')
        {
            location.append('/');
        }
    }
    return location;
}
#endif



DesktopHandler::DesktopHandler()
{
    mExecPath = qApp->applicationDirPath().append('/');
    mUseCustomDataPath = false;
    mUseCustomTempPath = false;
    mUseCustomDocumentsPath = false;
#if QT_VERSION >= 0x050000
    mDefaultConfigPath = getStandardLocation(QStandardPaths::ConfigLocation);
    mDefaultDataPath = getStandardLocation(QStandardPaths::DataLocation);
    mDefaultTempPath = getStandardLocation(QStandardPaths::TempLocation) + "Hopsan/";
    mDefaultDocumentsPath = getStandardLocation(QStandardPaths::DocumentsLocation) + "Hopsan/";
#else
    mDefaultDataPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/Hopsan/";
    mDefaultConfigPath = mDefaultDataPath;
    mDefaultTempPath = QDesktopServices::storageLocation(QDesktopServices::TempLocation) + "/Hopsan/";
    mDefaultDocumentsPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/Hopsan/";
    mDefaultDocumentsPath.replace("\\", "/");
#endif
    mBackupPath = mDefaultDocumentsPath+"Backup/";
    mModelsPath = mDefaultDocumentsPath+"Models/";
    mScriptsPath = mDefaultDocumentsPath+"Scripts/";
    mMainPath = mExecPath+"../";
    mHelpPath = mExecPath+"../doc/user/html/";
    mComponentsPath = mExecPath+"../componentLibraries/defaultLibrary/";
    mAutoLibsPath = mExecPath+"../componentLibraries/autoLibs/";
    mCoreIncludePath = mExecPath+"../HopsanCore/include/";
    mMSVC2008X86Path = mExecPath+"MSVC2008_x86/";
    mMSVC2010X86Path = mExecPath+"MSVC2010_x86/";
    mMSVC2008X64Path = mExecPath+"MSVC2008_x64/";
    mMSVC2010X64Path = mExecPath+"MSVC2010_x64/";
    mFMUPath = mDefaultDocumentsPath+"import/FMU/";
    mLogDataPath = mDefaultTempPath + "LogData/";
}


void DesktopHandler::setupPaths()
{
    //Make sure data path exists, ask user for custom path if default cannot be created
    QDir dataDir(mDefaultDataPath);
    if (!dataDir.exists())
    {
        dataDir.mkpath(mDefaultDataPath);
    }
    QFile dummyFile1(mDefaultDataPath+"HOPSANDUMMYTESTFILETHATWILLBEREMOVED");
    if(dummyFile1.exists())
    {
        dummyFile1.remove();
    }
    if (dummyFile1.open(QFile::ReadWrite))
    {
        qDebug() << "Data path is writable!";
    }
    else
    {
        dummyFile1.close();
        qDebug() << "Data path is NOT writable!";
        QMessageBox::information(0, "Choose data path", "Default data directory is not writable:\n\n"+mDefaultDataPath+"\n\nPlease choose a different path.", "Okay");
        QWidget *pWidget = new QWidget();
        QFileDialog *pDialog = new QFileDialog(pWidget);
        mCustomDocumentsPath = pDialog->getExistingDirectory(pWidget, "Choose Data Directory",
                                mExecPath,
                                QFileDialog::ShowDirsOnly
                                | QFileDialog::DontResolveSymlinks);
        delete(pDialog);
        delete(pWidget);
        mUseCustomDocumentsPath = true;
    }
    dummyFile1.remove();


    //Make sure documents path exists, ask user for custom path if default cannot be created
    QDir documentsDir(mDefaultDocumentsPath);
    if (!documentsDir.exists())
    {
        documentsDir.mkpath(mDefaultDocumentsPath);
    }
    QFile dummyFile2(mDefaultDocumentsPath+"HOPSANDUMMYTESTFILETHATWILLBEREMOVED");
    if(dummyFile2.exists())
    {
        dummyFile2.remove();
    }
    if (dummyFile2.open(QFile::ReadWrite))
    {
        qDebug() << "Documents path is writable!";
    }
    else
    {
        dummyFile2.close();
        qDebug() << "Documents path is NOT writable!";
        QMessageBox::information(0, "Choose documents path", "Default documents directory is not writable:\n\n"+mDefaultDocumentsPath+"\n\nPlease choose a different path.", "Okay");
        QWidget *pWidget = new QWidget();
        QFileDialog *pDialog = new QFileDialog(pWidget);
        mCustomDocumentsPath = pDialog->getExistingDirectory(pWidget, "Choose Documents Directory",
                                mExecPath,
                                QFileDialog::ShowDirsOnly
                                | QFileDialog::DontResolveSymlinks);
        mCustomDocumentsPath.append('/');
        delete(pDialog);
        delete(pWidget);
        mUseCustomDocumentsPath = true;
    }
    dummyFile2.remove();


    //Update paths depending on data, temp and documents paths
    mBackupPath = getDocumentsPath()+"Backup/";
    mModelsPath = getDocumentsPath()+"Models/";
    mScriptsPath = getDocumentsPath()+"Scripts/";
    mLogDataPath = getTempPath()+"LogData/";
    mFMUPath = getDocumentsPath()+"import/FMU/";

     // Make sure backup folder exists, create it if not
    if (!QDir().exists(getBackupPath()))
    {
        QDir().mkpath(getBackupPath());
    }

    // Make sure model folder exists, create it if not, if create not sucessful use dev dir
    if (!QDir().exists(getModelsPath()))
    {
        QDir().mkpath(getModelsPath());
    }

    // Select which scripts path to use, create it if not, if create not sucessful use dev dir
    //! @todo problem in linux if scripts must be changed, as they  are not installed to user home
    if (!QDir().exists(getScriptsPath()))
    {
        QDir().mkpath(getScriptsPath());
    }

    // Clear cache folders from left over junk (if Hopsan crashed last time, or was unable to cleanup)
    qDebug() << "LogdataCache: " << getLogDataPath();
    removeDir(getLogDataPath());
}
<commit_msg>Improved the code that checks if some default directories are writable, now checks data dir documents dir and temp dir. Related to #1411<commit_after>/*-----------------------------------------------------------------------------
 This source file is part of Hopsan NG

 Copyright (c) 2011
    <NAME>, <NAME>, <NAME>, <NAME>,
    <NAME>, <NAME>, <NAME>, <NAME>

 This file is provided "as is", with no guarantee or warranty for the
 functionality or reliability of the contents. All contents in this file is
 the original work of the copyright holders at the Division of Fluid and
 Mechatronic Systems (Flumes) at Linköping University. Modifying, using or
 redistributing any part of this file is prohibited without explicit
 permission from the copyright holders.
-----------------------------------------------------------------------------*/

//!
//! @file   DesktopHandler.cpp
//! @author <NAME> <<EMAIL>>
//! @date   2013-03-13
//!
//! @brief Contains a utility class for handling desktop interaction, especially paths
//!
//$Id$

#include "DesktopHandler.h"
#include "common.h"

#include <QDesktopServices>
#include <QString>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QApplication>
#include "Utilities/GUIUtilities.h"

#if QT_VERSION >= 0x050000
#include <QStandardPaths>
QString getStandardLocation(QStandardPaths::StandardLocation type)
{
    QString location;
    QStringList locations = QStandardPaths::standardLocations(type);
    if (!locations.isEmpty())
    {
        // Take first reported location
        location = locations.first();
        // Append '/' to end if not already present
        if (location[location.size()-1] != '/')
        {
            location.append('/');
        }
    }
    return location;
}
#endif

bool testIfDirectoryIsWritable(QDir &rDir)
{
    if (rDir.exists())
    {
        bool rc = true;
        QFile dummyFile(rDir.absoluteFilePath("HOPSANDUMMYTESTFILETHATWILLBEREMOVED"));
        // Remove file if it already exists
        if(dummyFile.exists())
        {
            rc = dummyFile.remove();
        }
        // If we could remove it (and or if we can open a new one (writeable) then all is good
        if (rc && dummyFile.open(QFile::ReadWrite))
        {
            qDebug() << rDir.absolutePath() << " is writable!";
        }
        // Else it is not so good
        else
        {
            qDebug() << rDir.absolutePath() << " is NOT writable!";
            rc = false;
        }
        dummyFile.close();
        dummyFile.remove();
        return rc;
    }
    return false;
}

bool mkpath(const QDir &rDir)
{
    // No need to check if it exists first, mkpath does that internally
    return rDir.mkpath(rDir.absolutePath());
}

bool mkpath(const QString &rPath)
{
    return mkpath(QDir(rPath));
}


DesktopHandler::DesktopHandler()
{
    mExecPath = qApp->applicationDirPath().append('/');
    mUseCustomDataPath = false;
    mUseCustomTempPath = false;
    mUseCustomDocumentsPath = false;
#if QT_VERSION >= 0x050000
    mDefaultConfigPath = getStandardLocation(QStandardPaths::ConfigLocation);
    mDefaultDataPath = getStandardLocation(QStandardPaths::DataLocation);
    mDefaultTempPath = getStandardLocation(QStandardPaths::TempLocation) + "Hopsan/";
    mDefaultDocumentsPath = getStandardLocation(QStandardPaths::DocumentsLocation) + "Hopsan/";
#else
    mDefaultDataPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/Hopsan/";
    mDefaultConfigPath = mDefaultDataPath;
    mDefaultTempPath = QDesktopServices::storageLocation(QDesktopServices::TempLocation) + "/Hopsan/";
    mDefaultDocumentsPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/Hopsan/";
    mDefaultDocumentsPath.replace("\\", "/");
#endif
    mBackupPath = mDefaultDocumentsPath+"Backup/";
    mModelsPath = mDefaultDocumentsPath+"Models/";
    mScriptsPath = mDefaultDocumentsPath+"Scripts/";
    mMainPath = mExecPath+"../";
    mHelpPath = mExecPath+"../doc/user/html/";
    mComponentsPath = mExecPath+"../componentLibraries/defaultLibrary/";
    mAutoLibsPath = mExecPath+"../componentLibraries/autoLibs/";
    mCoreIncludePath = mExecPath+"../HopsanCore/include/";
    mMSVC2008X86Path = mExecPath+"MSVC2008_x86/";
    mMSVC2010X86Path = mExecPath+"MSVC2010_x86/";
    mMSVC2008X64Path = mExecPath+"MSVC2008_x64/";
    mMSVC2010X64Path = mExecPath+"MSVC2010_x64/";
    mFMUPath = mDefaultDocumentsPath+"import/FMU/";
    mLogDataPath = mDefaultTempPath + "LogData/";
}


void DesktopHandler::setupPaths()
{
    // Make sure data path exists, ask user for custom path if default cannot be created
    QDir dataDir(mDefaultDataPath);
    mkpath(dataDir);
    if (!testIfDirectoryIsWritable(dataDir))
    {
        QDir customDir;
        do
        {
            QMessageBox::information(0, "Choose data path", "Default data directory is not writable:\n\n"+mDefaultDataPath+"\n\nPlease choose a different path.", "Okay");
            QWidget *pWidget = new QWidget();
            QFileDialog *pDialog = new QFileDialog(pWidget);
            mCustomDataPath = pDialog->getExistingDirectory(pWidget, "Choose Data Directory",
                                                            mExecPath,
                                                            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
            mCustomDataPath.append("/");
            customDir.setPath(mCustomDataPath);
            mkpath(customDir);
            pDialog->deleteLater();
            pWidget->deleteLater();
        }while(!testIfDirectoryIsWritable(customDir));
        mUseCustomDataPath = true;
    }

    // Make sure documents path exists, ask user for custom path if default cannot be created
    QDir documentsDir(mDefaultDocumentsPath);
    mkpath(documentsDir);
    if(!testIfDirectoryIsWritable(documentsDir))
    {
        QDir customDir;
        do
        {
            QMessageBox::information(0, "Choose documents path", "Default documents directory is not writable:\n\n"+mDefaultDocumentsPath+"\n\nPlease choose a different path.", "Okay");
            QWidget *pWidget = new QWidget();
            QFileDialog *pDialog = new QFileDialog(pWidget);
            mCustomDocumentsPath = pDialog->getExistingDirectory(pWidget, "Choose Documents Directory",
                                    mExecPath,
                                    QFileDialog::ShowDirsOnly
                                    | QFileDialog::DontResolveSymlinks);
            mCustomDocumentsPath.append('/');
            customDir.setPath(mCustomDocumentsPath);
            mkpath(customDir);
            pDialog->deleteLater();
            pWidget->deleteLater();
        }while(!testIfDirectoryIsWritable(customDir));
        mUseCustomDocumentsPath = true;
    }

    // Make sure temp path exists, ask user for custom path if default cannot be created
    QDir tempDir(mDefaultTempPath);
    mkpath(tempDir);
    if (!testIfDirectoryIsWritable(tempDir))
    {
        QDir customDir;
        do
        {
            QMessageBox::information(0, "Choose temp path", "Default temp directory is not writable:\n\n"+mDefaultTempPath+"\n\nPlease choose a different path.", "Okay");
            QWidget *pWidget = new QWidget();
            QFileDialog *pDialog = new QFileDialog(pWidget);
            mCustomTempPath = pDialog->getExistingDirectory(pWidget, "Choose Temp Directory",
                                                            mExecPath,
                                                            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
            mCustomTempPath.append("/");
            customDir.setPath(mCustomTempPath);
            mkpath(customDir);
            pDialog->deleteLater();
            pWidget->deleteLater();
        }while(!testIfDirectoryIsWritable(customDir));
        mUseCustomTempPath = true;
    }

    // Update paths depending on data, temp and documents paths
    mBackupPath = getDocumentsPath()+"Backup/";
    mModelsPath = getDocumentsPath()+"Models/";
    mScriptsPath = getDocumentsPath()+"Scripts/";
    mFMUPath = getDocumentsPath()+"import/FMU/";
    mLogDataPath = getTempPath()+"LogData/";

     // Make sure backup folder exists, create it if not
    mkpath(getBackupPath());

    // Make sure model folder exists, create it if not, if create not sucessful use dev dir
    mkpath(getModelsPath());

    // Select which scripts path to use, create it if not, if create not sucessful use dev dir
    //! @todo problem in linux if scripts must be changed, as they  are not installed to user home
    mkpath(getScriptsPath());

    // Clear cache folders from left over junk (if Hopsan crashed last time, or was unable to cleanup)
    qDebug() << "LogdataCache: " << getLogDataPath();
    removeDir(getLogDataPath());
}

{'fraction_non_alphanumeric': 0.1281293244433262, 'fraction_numerical': 0.010756069945905146, 'mean_word_length': 2.787279656979514, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 13, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '787785', 'n_tokens_mistral': 4626, 'n_tokens_neox': 4375, 'n_words': 1106}