<commit_before>import logging
import mimetypes
import os
import uuid
from pyqode.qt import QtCore, QtWidgets, QtGui
from pyqode.core.api import utils, CodeEdit, ColorScheme
from pyqode.core.dialogs import DlgUnsavedFiles
from .tab_bar import TabBar
from .code_edits import GenericCodeEdit, TextCodeEdit


def _logger():
    return logging.getLogger(__name__)


class DraggableTabBar(TabBar):
    """
    A draggable tab bar that allow to drag & drop tabs.

    Implementation is based on this qt article:
    http://www.qtcentre.org/wiki/index.php?title=Movable_Tabs
    """
    #: Signal emitted when a tab must be moved to the specified
    #: index (the tab might come from another tab bar (split)).
    tab_move_request = QtCore.Signal(QtWidgets.QWidget, int)

    def __init__(self, parent):
        super(DraggableTabBar, self).__init__(parent)
        self._pos = QtCore.QPoint()
        self.setAcceptDrops(True)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self._pos = event.pos()  # _pos is a QPoint defined in the header
        super(DraggableTabBar, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        # If the distance is too small then return
        if (event.pos() - self._pos).manhattanLength() < \
                QtWidgets.QApplication.startDragDistance():
            return

        # If the left button isn't pressed anymore then return
        if not event.buttons() & QtCore.Qt.LeftButton:
            return

        drag = QtGui.QDrag(self)
        data = QtCore.QMimeData()
        data.tab = self.parent().currentWidget()
        data.widget = self
        # a crude way to distinguish tab-reodering drags from other drags
        data.setData("action", "tab-reordering")
        drag.setMimeData(data)
        drag.setPixmap(self.tabIcon(self.tabAt(event.pos())).pixmap(32, 32))
        drag.exec_()

    def dragEnterEvent(self, event):
        # Only accept if it's an tab-reordering request
        m = event.mimeData()
        formats = m.formats()
        if "action" in formats and m.data("action") == "tab-reordering":
            event.acceptProposedAction()

    def dropEvent(self, event):
        m = event.mimeData()
        index = self.tabAt(event.pos())
        # Tell interested objects that a tab should be moved.
        if m.tab != self.parent().widget(index):
            self.tab_move_request.emit(m.tab, index)
        event.acceptProposedAction()


class BaseTabWidget(QtWidgets.QTabWidget):
    """
    Base tab widget class used by SplittableTabWidget. This tab widget adds a
    context menu to the tab bar that allow the user to:
        - split the current tab (horizontally or vertically)
        - close the current tab
        - close all tabs
        - close all other tabs

    The easiest way to add custom actions to the tab context menu is to
    override the ``_create_context_menu`` method.
    """
    #: Signal emitted when the last tab has been closed
    last_tab_closed = QtCore.Signal()
    #: Signal emitted when a tab has been closed
    tab_closed = QtCore.Signal(QtWidgets.QWidget)
    #: Signal emitted when the user clicked on split vertical or split
    #: horizontal
    #: **Parameters**:
    #: - widget: the widget to split
    #: - orientation: split orientation (horizontal/vertical)
    split_requested = QtCore.Signal(QtWidgets.QWidget, int)

    def __init__(self, parent):
        super(BaseTabWidget, self).__init__(parent)
        self._current = None
        self.currentChanged.connect(self._on_current_changed)
        self.tabCloseRequested.connect(self._on_tab_close_requested)

        tab_bar = DraggableTabBar(self)
        tab_bar.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        tab_bar.customContextMenuRequested.connect(self._show_tab_context_menu)
        tab_bar.tab_move_request.connect(self._on_tab_move_request)
        self.setTabBar(tab_bar)
        self._context_mnu = self._create_tab_bar_menu()
        self.setAcceptDrops(True)

    def tab_under_menu(self):
        return self.tabBar().tabAt(self._menu_pos)

    @QtCore.Slot()
    def close(self):
        """
        Closes the active editor
        """
        self.tabCloseRequested.emit(self.tab_under_menu())

    @QtCore.Slot()
    def close_others(self):
        """
        Closes every editors tabs except the current one.
        """
        current_widget = self.widget(self.tab_under_menu())
        self._try_close_dirty_tabs(exept=current_widget)
        i = 0
        while self.count() > 1:
            widget = self.widget(i)
            if widget != current_widget:
                self.remove_tab(i)
            else:
                i = 1

    @QtCore.Slot()
    def close_all(self):
        """
        Closes all editors
        """
        if self._try_close_dirty_tabs():
            while self.count():
                widget = self.widget(0)
                self.remove_tab(0)
                self.tab_closed.emit(widget)
            return True
        return False

    def save_widget(self, editor):
        """
        Saves the widget. The base implementation does nothing.

        The function must return a bool that tells whether the save 
        succeeded or not.
        """
        return True

    def _create_tab_bar_menu(self):
        _context_mnu = QtWidgets.QMenu()
        menu = QtWidgets.QMenu('Split', _context_mnu)
        menu.addAction('Split horizontally').triggered.connect(
            self._on_split_requested)
        menu.addAction('Split vertically').triggered.connect(
            self._on_split_requested)
        _context_mnu.addMenu(menu)
        _context_mnu.addSeparator()
        for name, slot in [('Close', self.close),
                           ('Close others', self.close_others),
                           ('Close all', self.close_all)]:
            qaction = QtWidgets.QAction(name, self)
            qaction.triggered.connect(slot)
            _context_mnu.addAction(qaction)
            self.addAction(qaction)
        return _context_mnu

    def _show_tab_context_menu(self, position):
        self._menu_pos = position
        # self._context_mnu.popup(self.mapToGlobal(position))
        self._context_mnu.popup(self.tabBar().mapToGlobal(position))

    def _collect_dirty_tabs(self, skip=None):
        """
        Collects the list of dirty tabs

        :param skip: Tab to skip (used for close_others).
        """
        widgets = []
        filenames = []
        for i in range(self.count()):
            widget = self.widget(i)
            try:
                if widget.dirty and widget != skip:
                    widgets.append(widget)
                    filenames.append(widget.file.path)
            except AttributeError:
                pass
        return widgets, filenames

    def _try_close_dirty_tabs(self, exept=None):
        """
        Tries to close dirty tabs. Uses DlgUnsavedFiles to ask the user
        what he wants to do.
        """
        widgets, filenames = self._collect_dirty_tabs(skip=exept)
        if not len(filenames):<commit_msg>Do not show tab context menu if there is not tab^^<commit_after>import logging
import mimetypes
import os
import uuid
from pyqode.qt import QtCore, QtWidgets, QtGui
from pyqode.core.api import utils, CodeEdit, ColorScheme
from pyqode.core.dialogs import DlgUnsavedFiles
from .tab_bar import TabBar
from .code_edits import GenericCodeEdit, TextCodeEdit


def _logger():
    return logging.getLogger(__name__)


class DraggableTabBar(TabBar):
    """
    A draggable tab bar that allow to drag & drop tabs.

    Implementation is based on this qt article:
    http://www.qtcentre.org/wiki/index.php?title=Movable_Tabs
    """
    #: Signal emitted when a tab must be moved to the specified
    #: index (the tab might come from another tab bar (split)).
    tab_move_request = QtCore.Signal(QtWidgets.QWidget, int)

    def __init__(self, parent):
        super(DraggableTabBar, self).__init__(parent)
        self._pos = QtCore.QPoint()
        self.setAcceptDrops(True)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self._pos = event.pos()  # _pos is a QPoint defined in the header
        super(DraggableTabBar, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        # If the distance is too small then return
        if (event.pos() - self._pos).manhattanLength() < \
                QtWidgets.QApplication.startDragDistance():
            return

        # If the left button isn't pressed anymore then return
        if not event.buttons() & QtCore.Qt.LeftButton:
            return

        drag = QtGui.QDrag(self)
        data = QtCore.QMimeData()
        data.tab = self.parent().currentWidget()
        data.widget = self
        # a crude way to distinguish tab-reodering drags from other drags
        data.setData("action", "tab-reordering")
        drag.setMimeData(data)
        drag.setPixmap(self.tabIcon(self.tabAt(event.pos())).pixmap(32, 32))
        drag.exec_()

    def dragEnterEvent(self, event):
        # Only accept if it's an tab-reordering request
        m = event.mimeData()
        formats = m.formats()
        if "action" in formats and m.data("action") == "tab-reordering":
            event.acceptProposedAction()

    def dropEvent(self, event):
        m = event.mimeData()
        index = self.tabAt(event.pos())
        # Tell interested objects that a tab should be moved.
        if m.tab != self.parent().widget(index):
            self.tab_move_request.emit(m.tab, index)
        event.acceptProposedAction()


class BaseTabWidget(QtWidgets.QTabWidget):
    """
    Base tab widget class used by SplittableTabWidget. This tab widget adds a
    context menu to the tab bar that allow the user to:
        - split the current tab (horizontally or vertically)
        - close the current tab
        - close all tabs
        - close all other tabs

    The easiest way to add custom actions to the tab context menu is to
    override the ``_create_context_menu`` method.
    """
    #: Signal emitted when the last tab has been closed
    last_tab_closed = QtCore.Signal()
    #: Signal emitted when a tab has been closed
    tab_closed = QtCore.Signal(QtWidgets.QWidget)
    #: Signal emitted when the user clicked on split vertical or split
    #: horizontal
    #: **Parameters**:
    #: - widget: the widget to split
    #: - orientation: split orientation (horizontal/vertical)
    split_requested = QtCore.Signal(QtWidgets.QWidget, int)

    def __init__(self, parent):
        super(BaseTabWidget, self).__init__(parent)
        self._current = None
        self.currentChanged.connect(self._on_current_changed)
        self.tabCloseRequested.connect(self._on_tab_close_requested)

        tab_bar = DraggableTabBar(self)
        tab_bar.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        tab_bar.customContextMenuRequested.connect(self._show_tab_context_menu)
        tab_bar.tab_move_request.connect(self._on_tab_move_request)
        self.setTabBar(tab_bar)
        self._context_mnu = self._create_tab_bar_menu()
        self.setAcceptDrops(True)

    def tab_under_menu(self):
        return self.tabBar().tabAt(self._menu_pos)

    @QtCore.Slot()
    def close(self):
        """
        Closes the active editor
        """
        self.tabCloseRequested.emit(self.tab_under_menu())

    @QtCore.Slot()
    def close_others(self):
        """
        Closes every editors tabs except the current one.
        """
        current_widget = self.widget(self.tab_under_menu())
        self._try_close_dirty_tabs(exept=current_widget)
        i = 0
        while self.count() > 1:
            widget = self.widget(i)
            if widget != current_widget:
                self.remove_tab(i)
            else:
                i = 1

    @QtCore.Slot()
    def close_all(self):
        """
        Closes all editors
        """
        if self._try_close_dirty_tabs():
            while self.count():
                widget = self.widget(0)
                self.remove_tab(0)
                self.tab_closed.emit(widget)
            return True
        return False

    def save_widget(self, editor):
        """
        Saves the widget. The base implementation does nothing.

        The function must return a bool that tells whether the save 
        succeeded or not.
        """
        return True

    def _create_tab_bar_menu(self):
        _context_mnu = QtWidgets.QMenu()
        menu = QtWidgets.QMenu('Split', _context_mnu)
        menu.addAction('Split horizontally').triggered.connect(
            self._on_split_requested)
        menu.addAction('Split vertically').triggered.connect(
            self._on_split_requested)
        _context_mnu.addMenu(menu)
        _context_mnu.addSeparator()
        for name, slot in [('Close', self.close),
                           ('Close others', self.close_others),
                           ('Close all', self.close_all)]:
            qaction = QtWidgets.QAction(name, self)
            qaction.triggered.connect(slot)
            _context_mnu.addAction(qaction)
            self.addAction(qaction)
        return _context_mnu

    def _show_tab_context_menu(self, position):
        if self.count():
            self._menu_pos = position
            # self._context_mnu.popup(self.mapToGlobal(position))
            self._context_mnu.popup(self.tabBar().mapToGlobal(position))

    def _collect_dirty_tabs(self, skip=None):
        """
        Collects the list of dirty tabs

        :param skip: Tab to skip (used for close_others).
        """
        widgets = []
        filenames = []
        for i in range(self.count()):
            widget = self.widget(i)
            try:
                if widget.dirty and widget != skip:
                    widgets.append(widget)
                    filenames.append(widget.file.path)
            except AttributeError:
                pass
        return widgets, filenames

    def _try_close_dirty_tabs(self, exept=None):
        """
        Tries to close dirty tabs. Uses DlgUnsavedFiles to ask the user
        what he wants to do.
        """
        widgets, filenames = self._collect_dirty_tabs(skip=exept)
        if not len(filenames):
{'fraction_non_alphanumeric': 0.09186241610738255, 'fraction_numerical': 0.0012583892617449664, 'mean_word_length': 2.3082793709528215, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, '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': '1779389', 'n_tokens_mistral': 4235, 'n_tokens_neox': 4064, 'n_words': 1053}