text: Q:
  
  Overwrite a controller and a block in magento
  
  I want to add a custom tab in catalog_product_edit page with my custom module. I want this tab of ajax type, since the tab holds grid content.
  To achieve this I rewrite the Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php block with my Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php block. It successfully rewrote the core block. My custom tab appeared in the edit page, but while click on the tab, it didnt work properly. 
  I have gone through the core files, and I found that, for ajax tabs, the action is defined in the controller Mage/Adminhtml/controllers/Catalog/ProductController.php. So I assumed the problem occurs due to my tabs action is not present in the core controller. So I planned to rewrite the above controller with myown Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php. When I rewrote the controller, edit page now shows nothing. 
  my app/code/local/Mysite/Combooffers/etc/config.xml
  <config>
  <modules>
      <Mysite_Combooffers>
          <version>0.1.0</version>
      </Mysite_Combooffers>
  </modules>
  <frontend>
      <routers>
          <Combooffers>
              <use>standard</use>
              <args>
                  <module>Mysite_Combooffers</module>
                  <frontName>combooffers</frontName>
              </args>
          </Combooffers>
      </routers>
      <layout>
          <updates>
              <combooffers>
                  <file>combooffers.xml</file>
              </combooffers>
          </updates>
      </layout>
  </frontend>
  <admin>
      <routers>
           <adminhtml>
              <args>
                  <modules>
                      <Mysite_Combooffers before="Mage_Adminhtml">Mysite_Combooffers_Adminhtml</Mysite_Combooffers>
                  </modules>
              </args>
          </adminhtml>
      </routers>
  </admin>
  <adminhtml>
      <layout>
          <updates>
              <combooffers>
                  <file>combooffers.xml</file>
              </combooffers>
          </updates>
      </layout>
  </adminhtml>
  <global>
      <blocks>
          <combooffers>
              <class>Mysite_Combooffers_Block</class>
              <sort_order>200</sort_order>
          </combooffers>
          <adminhtml>            
              <rewrite>  
                  <catalog_product_edit_tabs>
                          Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs
                  </catalog_product_edit_tabs> 
              </rewrite>  
          </adminhtml>
      </blocks>
      <routers>
          <adminhtml>
             <rewrite>
                    <mysite_combooffers_adminhtml_catalog_product>
                        <from><![CDATA[#^admin/catalog_product/$#]]></from>
                        <to>/admin/catalog_product/</to>
                    </mysite_combooffers_adminhtml_catalog_product>
              </rewrite>
         </adminhtml>
      </routers>
      <helpers>
          <combooffers>
              <class>Mysite_Combooffers_Helper</class>
          </combooffers>
      </helpers>
  </global>
  </config>
  
  app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php
  <?php
  
  class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs
  {
      protected function _prepareLayout()
      {
          /**Loads our tab using ajax.
              * ajax tab loads while click on the tab on edit page. Normally use to load grid content.
              * its complex
              * url is the important  one. when click on the tab, it will search for action correspond to the url in the controller.
              * here the action name should be `comboofferAction()`
          */
          $this->addTab('combooffer', array(
                  'label'     => Mage::helper('catalog')->__('Combo Products'),
                  'url'       => $this->getUrl('*/*/combooffer', array('_current' => true)),
                  'class'     => 'ajax',
                  'after'     => 'crosssell', //this will set tab after cross-sell tab.
              ));
  
          return parent::_prepareLayout();
      }
  } 
  
  app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Products/Edit/Tab/Combooffer.php 
  <?php
  
   class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tab_Combooffer extends Mage_Adminhtml_Block_Widget_Form
   {
  /**
   * Set grid params
   *
   */
  public function __construct()
  {
      parent::__construct();
      $this->setId('combo_offers_product_grid');
      $this->setDefaultSort('entity_id');
      $this->setUseAjax(true);  // Using ajax grid is important
      if ($this->_getProduct()->getId()) {
          $this->setDefaultFilter(array('in_products'=>1)); // By default we have added a filter for the rows, 
                                                            //that in_products value to be 1
      }
     // if ($this->isReadonly()) {
     //     $this->setFilterVisibility(false);
      //}
      $this->setSaveParametersInSession(false);  //Dont save paramters in session or else it creates problems
  }
  
  /**
   * Retirve currently edited product model
   *
   * @return Mage_Catalog_Model_Product
   */
  protected function _getProduct()
  {
      return Mage::registry('current_product');
  }
  
  /**
   * Add filter
   *
   * @param object $column
   * @return Mysite_Combooffers_Adminhtml_Block_Catalog_Product_Edit_Tab_Combooffer
   */
  protected function _addColumnFilterToCollection($column)
  {
      // Set custom filter for in product flag
      if ($column->getId() == 'in_products') {
          $productIds = $this->_getSelectedComboOffers();
          if (empty($productIds)) {
              $productIds = 0;
          }
          if ($column->getFilter()->getValue()) {
              $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds));
          } else {
              if($productIds) {
                  $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds));
              }
          }
      } else {
          parent::_addColumnFilterToCollection($column);
      }
      return $this;
  }
  
  /**
   * Prepare collection
   *
   * @return Mage_Adminhtml_Block_Widget_Grid
   */
  protected function _prepareCollection()
  {
      $collection = Mage::getModel('catalog/product_link')->useUpSellLinks()
          ->getProductCollection()
          ->setProduct($this->_getProduct())
          ->addAttributeToSelect('*');
  
      if ($this->isReadonly()) {
          $productIds = $this->_getSelectedProducts();
          if (empty($productIds)) {
              $productIds = array(0);
          }
          $collection->addFieldToFilter('entity_id', array('in'=>$productIds));
      }
  
      $this->setCollection($collection);
      return parent::_prepareCollection();
  }
  
  /**
   * Add columns to grid
   *
   * @return Mage_Adminhtml_Block_Widget_Grid
   */
  protected function _prepareColumns()
  {
      if (!$this->_getProduct()->getUpsellReadonly()) {
          $this->addColumn('in_products', array(
              'header_css_class' => 'a-center',
              'type'      => 'checkbox',
              'name'      => 'in_products',
              'values'    => $this->_getSelectedComboOffers(),
              'align'     => 'center',
              'index'     => 'entity_id'
          ));
      }
  
      $this->addColumn('entity_id', array(
          'header'    => Mage::helper('catalog')->__('ID'),
          'sortable'  => true,
          'width'     => 60,
          'index'     => 'entity_id'
      ));
      $this->addColumn('name', array(
          'header'    => Mage::helper('catalog')->__('Name'),
          'index'     => 'name'
      ));
  
      $this->addColumn('type', array(
          'header'    => Mage::helper('catalog')->__('Type'),
          'width'     => 100,
          'index'     => 'type_id',
          'type'      => 'options',
          'options'   => Mage::getSingleton('catalog/product_type')->getOptionArray(),
      ));
  
      $sets = Mage::getResourceModel('eav/entity_attribute_set_collection')
          ->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
          ->load()
          ->toOptionHash();
  
      $this->addColumn('set_name', array(
          'header'    => Mage::helper('catalog')->__('Attrib. Set Name'),
          'width'     => 130,
          'index'     => 'attribute_set_id',
          'type'      => 'options',
          'options'   => $sets,
      ));
  
      $this->addColumn('status', array(
          'header'    => Mage::helper('catalog')->__('Status'),
          'width'     => 90,
          'index'     => 'status',
          'type'      => 'options',
          'options'   => Mage::getSingleton('catalog/product_status')->getOptionArray(),
      ));
  
      $this->addColumn('visibility', array(
          'header'    => Mage::helper('catalog')->__('Visibility'),
          'width'     => 90,
          'index'     => 'visibility',
          'type'      => 'options',
          'options'   => Mage::getSingleton('catalog/product_visibility')->getOptionArray(),
      ));
  
      $this->addColumn('sku', array(
          'header'    => Mage::helper('catalog')->__('SKU'),
          'width'     => 80,
          'index'     => 'sku'
      ));
  
      $this->addColumn('price', array(
          'header'        => Mage::helper('catalog')->__('Price'),
          'type'          => 'currency',
          'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
          'index'         => 'price'
      ));
  
      $this->addColumn('position', array(
          'header'            => Mage::helper('catalog')->__('Position'),
          'name'              => 'position',
          'type'              => 'number',
          'width'             => 60,
          'validate_class'    => 'validate-number',
          'index'             => 'position',
          'editable'          => true,  //!$this->_getProduct()->getUpsellReadonly(),
          'edit_only'         => true  //!$this->_getProduct()->getId()
      ));
  
      return parent::_prepareColumns();
  }
  
  /**
   * Rerieve grid URL
   *
   * @return string
   */
  public function getGridUrl()
  {
      return $this->_getData('grid_url') ? $this->_getData('grid_url') : $this->getUrl('*/*/combooffer', array('_current'=>true));
  }
  
  /**
   * Retrieve selected combo offers
   *
   * @return array
   */
  protected function _getSelectedComboOffers()
  {
      $products = $this->getSelectedComboOffers();
      if (!is_array($products)) {
          $products = array_keys($this->getSelectedComboOffers());
      }
      return $products;
  }
  
  /**
   * Retrieve combo offers
   *
   * @return arraygetSelectedComboOffers
   */
  public function getSelectedComboOffers()
  {
      $products = array();
      foreach (Mage::registry('current_product')->getUpSellProducts() as $product) {
          $products[$product->getId()] = array('position' => $product->getPosition());
      }
      return $products;
  }
  
  }
  app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php
  <?php
  
  require_once('Mage/Adminhtml/controllers/Catalog/ProductController.php');
  
  class Mysite_Combooffers_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Catalog_ProductController
  {
      /** Use to set content of combo offer tab.
          * Defines layout of combo offer tab.
          * The layout defined here should present in app/design/adminhtml/default/default/<layout>.xml
      */
      public function comboofferAction()
      {
          $this->_initProduct();
          $this->loadLayout();
          $this->getLayout()->getBlock('catalog.product.edit.tab.combooffer')
              ->setProductsUpsell($this->getRequest()->getPost('products_combooffer', null));
          $this->renderLayout();
      }
  
  }
  
  app/design/adminhtml/default/default/layout/combooffers.xml
  <combooffers_adminhtml_combooffer_combooffer>
  <adminhtml_catalog_product_upsell>
      <block type="core/text_list" name="root" output="toHtml">
          <block type="adminhtml/catalog_product_edit_tab_upsell" name="catalog.product.edit.tab.combooffer"/>
          <block type="adminhtml/widget_grid_serializer" name="upsell_grid_serializer">
              <reference name="upsell_grid_serializer">
                  <action method="initSerializerBlock">                       
                   <grid_block_name>catalog.product.edit.tab.combooffer</grid_block_name>
                      <data_callback>getSelectedComboOffers</data_callback>
                      <hidden_input_name>links[combooffers]</hidden_input_name>
                      <reload_param_name>products_combooffer</reload_param_name>
                  </action>
                  <action method="addColumnInputName">
                      <input_name>position</input_name>
                  </action>
              </reference>
          </block>
      </block>
  </adminhtml_catalog_product_upsell>
  </combooffers_adminhtml_combooffer_combooffer>
  
  Is there any problem with my approach ? Am I in the right path? What is the error that I have made here? Please give your suggestions. Thanks in advance
  
  A:
  
  This part was the villain in my case
     <adminhtml>            
          <rewrite>  
              <catalog_product_edit_tabs>
                      Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs
              </catalog_product_edit_tabs> 
          </rewrite>  
      </adminhtml>
  
  As you can see, I have put unwanted spaces inside the node <catalog_product_edit_tabs /> and thats what make problem in my case.
  So it should be like this.
     <adminhtml>            
          <rewrite>  
              <catalog_product_edit_tabs>Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs</catalog_product_edit_tabs> 
          </rewrite>  
      </adminhtml>
  
  