def add_channel(self, chname, workspace=None,
                    num_images=None, settings=None,
                    settings_template=None,
                    settings_share=None, share_keylist=None):
        """Create a new Ginga channel.

        Parameters
        ----------
        chname : str
            The name of the channel to create.

        workspace : str or None
            The name of the workspace in which to create the channel

        num_images : int or None
            The cache size for the number of images to keep in memory

        settings : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences. If not given, one will be created.

        settings_template : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences template

        settings_share : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences instance to share with newly created settings

        share_keylist : list of str
            List of names of settings that should be shared

        Returns
        -------
        channel : `~ginga.misc.Bunch.Bunch`
            The channel info bunch.

        """
        with self.lock:
            if self.has_channel(chname):
                return self.get_channel(chname)

            if chname in self.ds.get_tabnames(None):
                raise ValueError("Tab name already in use: '%s'" % (chname))

            name = chname
            if settings is None:
                settings = self.prefs.create_category('channel_' + name)
                try:
                    settings.load(onError='raise')

                except Exception as e:
                    self.logger.warning("no saved preferences found for channel "
                                        "'%s': %s" % (name, str(e)))

                    # copy template settings to new channel
                    if settings_template is not None:
                        osettings = settings_template
                        osettings.copy_settings(settings)
                    else:
                        try:
                            # use channel_Image as a template if one was not
                            # provided
                            osettings = self.prefs.get_settings('channel_Image')
                            self.logger.debug("Copying settings from 'Image' to "
                                              "'%s'" % (name))
                            osettings.copy_settings(settings)
                        except KeyError:
                            pass

            if (share_keylist is not None) and (settings_share is not None):
                # caller wants us to share settings with another viewer
                settings_share.share_settings(settings, keylist=share_keylist)

            # Make sure these preferences are at least defined
            if num_images is None:
                num_images = settings.get('numImages',
                                          self.settings.get('numImages', 1))
            settings.set_defaults(switchnew=True, numImages=num_images,
                                  raisenew=True, genthumb=True,
                                  focus_indicator=False,
                                  preload_images=False, sort_order='loadtime')

            self.logger.debug("Adding channel '%s'" % (chname))
            channel = Channel(chname, self, datasrc=None,
                              settings=settings)

            bnch = self.add_viewer(chname, settings,
                                   workspace=workspace)
            # for debugging
            bnch.image_viewer.set_name('channel:%s' % (chname))

            opmon = self.get_plugin_manager(self.logger, self,
                                            self.ds, self.mm)

            channel.widget = bnch.widget
            channel.container = bnch.container
            channel.workspace = bnch.workspace
            channel.connect_viewer(bnch.image_viewer)
            channel.viewer = bnch.image_viewer
            # older name, should eventually be deprecated
            channel.fitsimage = bnch.image_viewer
            channel.opmon = opmon

            name = chname.lower()
            self.channel[name] = channel

            # Update the channels control
            self.channel_names.append(chname)
            self.channel_names.sort()

            if len(self.channel_names) == 1:
                self.cur_channel = channel

            # Prepare local plugins for this channel
            for spec in self.get_plugins():
                opname = spec.get('klass', spec.get('module'))
                if spec.get('ptype', 'global') == 'local':
                    opmon.load_plugin(opname, spec, chinfo=channel)

            self.make_gui_callback('add-channel', channel)
            return channel
Create a new Ginga channel.

        Parameters
        ----------
        chname : str
            The name of the channel to create.

        workspace : str or None
            The name of the workspace in which to create the channel

        num_images : int or None
            The cache size for the number of images to keep in memory

        settings : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences. If not given, one will be created.

        settings_template : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences template

        settings_share : `~ginga.misc.Settings.SettingGroup` or `None`
            Viewer preferences instance to share with newly created settings

        share_keylist : list of str
            List of names of settings that should be shared

        Returns
        -------
        channel : `~ginga.misc.Bunch.Bunch`
            The channel info bunch.