void OnlineViewerServerImpl::load(string name, string url)
{
    string filepath;

    QRegExp filePattern("(\\w+)://(.+)");
    if(filePattern.exactMatch(url.c_str())){
        string protocol = filePattern.cap(1).toStdString();
        if(protocol == "file"){
            filepath = filePattern.cap(2).toStdString();
        } else {
            mv->putln(
                fmt(_("OnlineViewer: The model file at \"%1%\" cannot be read. %2% protocol is not supported."))
                % url % protocol);
            return;
        }
    } else {
        filepath = url;
    }
        
    // search for registered body items
    BodyItemInfo* info = findInfo(name);
    if(info && info->bodyItem->filePath() == filepath){
        info->needToSelectLogItem = true;
        // mv->putln(fmt(_("OnlineViewer: \"%1%\" at \"%2%\" has already been loaded.")) % name % url);
        return;
    }
    
    // search for existing body items
    RootItem* rootItem = RootItem::instance();
    ItemList<BodyItem> bodyItems;
    bodyItems.extractChildItems(rootItem);
    for(int i=0; i < bodyItems.size(); ++i){
        BodyItemPtr bodyItem = bodyItems[i];
        if(bodyItem->name() == name && bodyItem->filePath() == filepath){
            registerBodyItem(bodyItem);
            return;
        }
    }
    // load a new body item
    BodyItemPtr bodyItem = new BodyItem();
    mv->putln(fmt(_("OnlineViewer: Loading \"%1%\" at \"%2%\"."))
              % name % url);
    mv->flush();
    if(!bodyItem->load(filepath)){
        mv->putln(fmt(_("OnlineViewer: Loading \"%1%\" failed.")) % name);

    } else {
        bodyItem->setName(name);
        ItemList<WorldItem> worldItems;
        if(worldItems.extractChildItems(rootItem)){
            worldItems.front()->addChildItem(bodyItem);
        } else {
            rootItem->addChildItem(bodyItem);
        }
        ItemTreeView::instance()->checkItem(bodyItem, true);
        registerBodyItem(bodyItem);
    }
}
void OnlineViewerServerImpl::registerBodyItem(BodyItemPtr bodyItem)
{
    BodyItemInfo info;

    info.bodyItem = bodyItem;
    info.needToSelectLogItem = true;

    info.bodyItemConnections.add(
        bodyItem->sigNameChanged().connect(
            boost::bind(&OnlineViewerServerImpl::onBodyItemNameChanged, this, bodyItem.get(), _1)));
    info.bodyItemConnections.add(
        bodyItem->sigDisconnectedFromRoot().connect(
            boost::bind(&OnlineViewerServerImpl::onBodyItemDetachedFromRoot, this, bodyItem.get())));

    bodyItemInfoMap.insert(make_pair(bodyItem->name(), info));
}