Replace ``oldApplet`` with ``newApplet`` in the window layout.

        If ``oldApplet`` is **None** then the currently active applet
        will be replaced. If ``windowObj`` is **None** then the
        currently active window is used.

        The ``oldApplet`` and ``newApplet`` parameters can either be
        instances of ``QtmacsApplet`` or strings denoting the applet
        IDs. In the latter case the ``qteGetAppletHandle`` method is
        used to fetch the respective applet instances.

        |Args|

        * ``newApplet`` (**QtmacsApplet**, **str**): applet to add.
        * ``oldApplet`` (**QtmacsApplet**, **str**): applet to replace.
        * ``windowObj`` (**QtmacsWindow**): the window in which to operate.

        |Returns|

        * **None**

        |Raises|

        * **QtmacsArgumentError** if at least one argument has an invalid type.

def qteReplaceAppletInLayout(self, newApplet: (QtmacsApplet, str),
                                 oldApplet: (QtmacsApplet, str)=None,
                                 windowObj: QtmacsWindow=None):
        """
        Replace ``oldApplet`` with ``newApplet`` in the window layout.

        If ``oldApplet`` is **None** then the currently active applet
        will be replaced. If ``windowObj`` is **None** then the
        currently active window is used.

        The ``oldApplet`` and ``newApplet`` parameters can either be
        instances of ``QtmacsApplet`` or strings denoting the applet
        IDs. In the latter case the ``qteGetAppletHandle`` method is
        used to fetch the respective applet instances.

        |Args|

        * ``newApplet`` (**QtmacsApplet**, **str**): applet to add.
        * ``oldApplet`` (**QtmacsApplet**, **str**): applet to replace.
        * ``windowObj`` (**QtmacsWindow**): the window in which to operate.

        |Returns|

        * **None**

        |Raises|

        * **QtmacsArgumentError** if at least one argument has an invalid type.
        """
        # If ``oldAppObj`` was specified by its ID (ie. a string) then
        # fetch the associated ``QtmacsApplet`` instance. If
        # ``oldAppObj`` is already an instance of ``QtmacsApplet``
        # then use it directly.
        if isinstance(oldApplet, str):
            oldAppObj = self.qteGetAppletHandle(oldApplet)
        else:
            oldAppObj = oldApplet

        # If ``newAppObj`` was specified by its ID (ie. a string) then
        # fetch the associated ``QtmacsApplet`` instance. If
        # ``newAppObj`` is already an instance of ``QtmacsApplet``
        # then use it directly.
        if isinstance(newApplet, str):
            newAppObj = self.qteGetAppletHandle(newApplet)
        else:
            newAppObj = newApplet

        # Use the currently active window if none was specified.
        if windowObj is None:
            windowObj = self.qteActiveWindow()
            if windowObj is None:
                msg = 'Cannot determine the currently active window.'
                self.qteLogger.warning(msg, stack_info=True)
                return

        # If the main splitter contains no applet then just add newAppObj.
        if windowObj.qteAppletSplitter.count() == 0:
            windowObj.qteAppletSplitter.qteAddWidget(newAppObj)
            return

        # If no oldAppObj was specified use the currently active one
        # instead. Do not use qteActiveApplet to determine it, though,
        # because it may point to a mini buffer. If it is, then we
        # need the last active Qtmacs applet. In either case, the
        # qteNextApplet method will take care of these distinctions.
        if oldAppObj is None:
            oldAppObj = self.qteNextApplet(numSkip=0, windowObj=windowObj)

        # Sanity check: the applet to replace must exist.
        if oldAppObj is None:
            msg = 'Applet to replace does not exist.'
            self.qteLogger.error(msg, stack_info=True)
            return

        # Sanity check: do nothing if the old- and new applet are the
        # same.
        if newAppObj is oldAppObj:
            return

        # Sanity check: do nothing if both applets are already
        # visible.
        if oldAppObj.qteIsVisible() and newAppObj.qteIsVisible():
            return

        # Search for the splitter that contains 'oldAppObj'.
        split = self._qteFindAppletInSplitter(
            oldAppObj, windowObj.qteAppletSplitter)
        if split is None:
            msg = ('Applet <b>{}</b> not replaced because it is not'
                   'in the layout.'.format(oldAppObj.qteAppletID()))
            self.qteLogger.warning(msg)
            return

        # Determine the position of oldAppObj inside the splitter.
        oldAppIdx = split.indexOf(oldAppObj)

        # Replace oldAppObj with newAppObj but maintain the widget sizes. To do
        # so, first insert newAppObj into the splitter at the position of
        # oldAppObj. Afterwards, remove oldAppObj by re-parenting it, make
        # it invisible, and restore the widget sizes.
        sizes = split.sizes()
        split.qteInsertWidget(oldAppIdx, newAppObj)
        oldAppObj.hide(True)
        split.setSizes(sizes)