<commit_before>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  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.

import os
import sys
import stat
from itertools import chain
import shutil
import robotide.controller.ctrlcommands
try:
    import subprocess32 as subprocess
except ImportError:
    import subprocess
from robotide.controller.dataloader import ExcludedDirectory, TestData

from robotide.publish import (RideDataFileRemoved, RideInitFileRemoved,
        RideDataChangedToDirty, RideDataDirtyCleared, RideSuiteAdded,
        RideItemSettingsChanged)
from robotide.publish.messages import RideDataFileSet, RideOpenResource
from robotide.robotapi import TestDataDirectory, TestCaseFile, ResourceFile
from robotide import utils

from .basecontroller import WithUndoRedoStacks, _BaseController, WithNamespace, ControllerWithParent
from .macrocontrollers import UserKeywordController
from .robotdata import NewTestCaseFile, NewTestDataDirectory
from robotide.utils import overrides
from .settingcontrollers import (DocumentationController, FixtureController,
        TimeoutController, TemplateController, DefaultTagsController,
        ForceTagsController)
from .tablecontrollers import (VariableTableController, TestCaseTableController,
        KeywordTableController, ImportSettingsController,
        MetadataListController, TestCaseController)
from robotide.utils import PY3
if PY3:
    from robotide.utils import basestring


def _get_controller(project, data, parent):
    if isinstance(data, TestCaseFile):
        return TestCaseFileController(data, project, parent)
    if isinstance(data, ExcludedDirectory):
        return ExcludedDirectoryController(data, project, parent)
    return TestDataDirectoryController(data, project, parent)


def DataController(data, project, parent=None):
    return _get_controller(project, data, parent)


class _FileSystemElement(object):

    def __init__(self, filename, directory):
        self.filename = filename
        self.directory = directory
        self._stat = self._get_stat(filename)

    def _get_stat(self, path):
        if path and os.path.isfile(path):
            stat = os.stat(path)
            return stat.st_mtime, stat.st_size
        return 0, 0

    def refresh_stat(self):
        self._stat = self._get_stat(self.filename)

    def has_been_modified_on_disk(self):
        return self._get_stat(self.filename) != self._stat

    def has_been_removed_from_disk(self):
        return self._stat != (0, 0) and not self.exists()

    def relative_path_to(self, other):
        other_path = os.path.join(other.directory, other.filename)
        return os.path.relpath(other_path, start=self.directory).replace('\\', '/')

    def is_readonly(self):
        return not os.access(self.filename, os.W_OK)

    def exists(self):
        return self.filename and os.path.isfile(self.filename)

    @property
    def basename(self):
        return os.path.splitext(os.path.basename(self.filename))[0]

    @property
    def source(self):
        """Deprecated, use ``filename`` or ``directory`` instead."""
        # Todo: remove when backwards compatibility with plugin API can break
        return self.filename or self.directory


class _DataController(_BaseController, WithUndoRedoStacks, WithNamespace):

    def __init__(self, data, project=None, parent=None):
        self._project = project
        if project:
            self._set_namespace_from(project)
            self._resource_file_controller_factory =\
                project.resource_file_controller_factory
        else:
            self._resource_file_controller_factory = None
        self.parent = parent
        self.set_datafile(data)
        self.dirty = False
        self.children = self._children(data)

    def set_datafile(self, datafile):
        self.data = datafile
        self._variables_table_controller = None
        self._testcase_table_controller = None
        self._keywords_table_controller = None
        self._imports = None
        RideDataFileSet(item=self).publish()

    def _children(self, data):
        return []

    @property
    def name(self):
        return self.data.name

    @property
    def settings(self):
        return self._settings()

    def _settings(self):
        ss = self.data.setting_table
        return [DocumentationController(self, ss.doc),<commit_msg>Initialized filename value, so that RIDE uses the file's path (instead of the directory path) (#1950)<commit_after>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  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.

import os
import sys
import stat
from itertools import chain
import shutil
import robotide.controller.ctrlcommands
try:
    import subprocess32 as subprocess
except ImportError:
    import subprocess
from robotide.controller.dataloader import ExcludedDirectory, TestData

from robotide.publish import (RideDataFileRemoved, RideInitFileRemoved,
        RideDataChangedToDirty, RideDataDirtyCleared, RideSuiteAdded,
        RideItemSettingsChanged)
from robotide.publish.messages import RideDataFileSet, RideOpenResource
from robotide.robotapi import TestDataDirectory, TestCaseFile, ResourceFile
from robotide import utils

from .basecontroller import WithUndoRedoStacks, _BaseController, WithNamespace, ControllerWithParent
from .macrocontrollers import UserKeywordController
from .robotdata import NewTestCaseFile, NewTestDataDirectory
from robotide.utils import overrides
from .settingcontrollers import (DocumentationController, FixtureController,
        TimeoutController, TemplateController, DefaultTagsController,
        ForceTagsController)
from .tablecontrollers import (VariableTableController, TestCaseTableController,
        KeywordTableController, ImportSettingsController,
        MetadataListController, TestCaseController)
from robotide.utils import PY3
if PY3:
    from robotide.utils import basestring


def _get_controller(project, data, parent):
    if isinstance(data, TestCaseFile):
        return TestCaseFileController(data, project, parent)
    if isinstance(data, ExcludedDirectory):
        return ExcludedDirectoryController(data, project, parent)
    return TestDataDirectoryController(data, project, parent)


def DataController(data, project, parent=None):
    return _get_controller(project, data, parent)


class _FileSystemElement(object):

    def __init__(self, filename, directory):
        self.filename = filename
        self.directory = directory
        self._stat = self._get_stat(filename)

    def _get_stat(self, path):
        if path and os.path.isfile(path):
            stat = os.stat(path)
            return stat.st_mtime, stat.st_size
        return 0, 0

    def refresh_stat(self):
        self._stat = self._get_stat(self.filename)

    def has_been_modified_on_disk(self):
        return self._get_stat(self.filename) != self._stat

    def has_been_removed_from_disk(self):
        return self._stat != (0, 0) and not self.exists()

    def relative_path_to(self, other):
        other_path = os.path.join(other.directory, other.filename)
        return os.path.relpath(other_path, start=self.directory).replace('\\', '/')

    def is_readonly(self):
        return not os.access(self.filename, os.W_OK)

    def exists(self):
        return self.filename and os.path.isfile(self.filename)

    @property
    def basename(self):
        return os.path.splitext(os.path.basename(self.filename))[0]

    @property
    def source(self):
        """Deprecated, use ``filename`` or ``directory`` instead."""
        # Todo: remove when backwards compatibility with plugin API can break
        return self.filename or self.directory


class _DataController(_BaseController, WithUndoRedoStacks, WithNamespace):

    def __init__(self, data, project=None, parent=None):
        self._project = project
        if project:
            self._set_namespace_from(project)
            self._resource_file_controller_factory =\
                project.resource_file_controller_factory
        else:
            self._resource_file_controller_factory = None
        self.parent = parent
        self.set_datafile(data)
        self.dirty = False
        self.children = self._children(data)
        # Filename needs to be set when creating a new datafile
        if hasattr(self.data, 'initfile'):
            self.filename = self.data.initfile
        else:
            self.filename = self.data.source

    def set_datafile(self, datafile):
        self.data = datafile
        self._variables_table_controller = None
        self._testcase_table_controller = None
        self._keywords_table_controller = None
        self._imports = None
        RideDataFileSet(item=self).publish()

    def _children(self, data):
        return []

    @property
    def name(self):
        return self.data.name

    @property
    def settings(self):
        return self._settings()

    def _settings(self):
        ss = self.data.setting_table
        return [DocumentationController(self, ss.doc),
{'fraction_non_alphanumeric': 0.0751164403924289, 'fraction_numerical': 0.005351303141413141, 'mean_word_length': 3.521505376344086, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4728532', 'n_tokens_mistral': 2773, 'n_tokens_neox': 2670, 'n_words': 778}