00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llfloaterimport.h"
00035 
00036 #include "llapr.h"
00037 
00038 #include "llimagebmp.h"
00039 #include "llimagetga.h"
00040 #include "llimagejpeg.h"
00041 
00042 #include "llagent.h"
00043 #include "llbutton.h"
00044 #include "llcombobox.h"
00045 #include "lldrawable.h"
00046 #include "lldrawpoolavatar.h"
00047 #include "llface.h"
00048 #include "llinventorymodel.h"
00049 #include "lllineeditor.h"
00050 #include "llresourcedata.h"
00051 #include "lltextbox.h"
00052 #include "lltoolmgr.h"
00053 #include "llui.h"
00054 #include "lluploaddialog.h"
00055 #include "llviewercamera.h"
00056 #include "llviewermenufile.h"   
00057 #include "llviewerwindow.h"
00058 #include "llvoavatar.h"
00059 #include "pipeline.h"
00060 #include "viewer.h"
00061 #include "llvieweruictrlfactory.h"
00062 #include "llmd5.h"
00063 
00064 extern LLInventoryModel gInventory;
00065 
00066 
00067 
00068 LLUUID LLFloaterImport::sImportRequestID;
00069 LLString        LLFloaterImport::sOKText = LLString();
00070 
00071 const S32 PREVIEW_BORDER_WIDTH = 2;
00072 const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
00073 const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
00074 const S32 PREF_BUTTON_HEIGHT = 16;
00075 const S32 PREVIEW_TEXTURE_HEIGHT = 300;
00076 
00077 
00078 
00079 
00080 LLFloaterImport::LLFloaterImport(const std::string filename)
00081         : LLFloater("Import")
00082 {
00083         mFilenameAndPath = filename;
00084 
00085         char file_path[256];    
00086         strncpy(file_path, mFilenameAndPath.c_str(), sizeof(file_path) -1);             
00087         file_path[sizeof(file_path) -1] = '\0';
00088         char *file_name = strrchr( file_path, gDirUtilp->getDirDelimiter()[0]);
00089         file_name[0] = 0;
00090 
00091         mFilename.assign(file_name + 1);
00092         mFilePath.assign(file_path);
00093 
00094         
00095         
00096         LLXMLNode::parseFile(filename, mObjectFile, NULL);
00097 }
00098 
00099 
00100 
00101 
00102 BOOL LLFloaterImport::postBuild()
00103 {
00104         LLString asset_name = mFilename;
00105         LLString::replaceNonstandardASCII( asset_name, '?' );
00106         LLString::replaceChar(asset_name, '|', '?');
00107         LLString::stripNonprintable(asset_name);
00108         LLString::trim(asset_name);
00109 
00110         char* asset_name_str = (char*)asset_name.c_str();
00111         char* end_p = strrchr(asset_name_str, '.');              
00112         if( !end_p )
00113         {
00114                 end_p = asset_name_str + strlen( asset_name_str );                      
00115         }
00116                 
00117         S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
00118 
00119         asset_name = asset_name.substr( 0, len );
00120 
00121         setTitle(mFilename);
00122 
00123         {
00124                 
00125                 LLRect window_rect = gViewerWindow->getRootView()->getRect();
00126 
00127                 S32 dialog_left = window_rect.mLeft + (window_rect.getWidth() - mRect.getWidth()) / 2;
00128                 S32 dialog_bottom = window_rect.mBottom + (window_rect.getHeight() - mRect.getHeight()) / 2;
00129 
00130                 translate( dialog_left - mRect.mLeft, dialog_bottom - mRect.mBottom );
00131         }
00132 
00133         mNameEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "name_form");
00134         mNameEditor->setMaxTextLength(DB_INV_ITEM_NAME_STR_LEN);
00135         
00136         mNameEditor->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe);
00137 
00138         mNameEditor->setText(asset_name);
00139 
00140         mDescEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "description_form");
00141         mDescEditor->setMaxTextLength(DB_INV_ITEM_DESC_STR_LEN);
00142         
00143         mDescEditor->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe);
00144 
00145         
00146         mCancelBtn = LLViewerUICtrlFactory::getButtonByName(this, "cancel_btn");
00147         mCancelBtn->setClickedCallback(onBtnCancel);
00148         mCancelBtn->setCallbackUserData(this);
00149 
00150         
00151         mOKBtn = LLViewerUICtrlFactory::getButtonByName(this, "ok_btn");
00152         mOKBtn->setClickedCallback(onBtnOK);
00153         mOKBtn->setCallbackUserData(this);
00154         setDefaultBtn(mOKBtn);
00155 
00156         mImageLabel = LLViewerUICtrlFactory::getTextBoxByName(this, "preview_label");
00157         mImportList = LLViewerUICtrlFactory::getScrollListByName(this, "upload_list");
00158 
00159         bool object_file_read = false;
00160         int object_count = 0, image_count = 0;
00161         if (mObjectFile)
00162         {
00163                 LLXMLNodeList object_list;
00164                 mObjectFile->findName("object", object_list);
00165                 LLXMLNodeList::iterator itor;
00166                 LLXMLNodeList::iterator itor2;
00167                 for (itor = object_list.begin(); itor != object_list.end(); ++itor)
00168                 {
00169                         LLXMLNode *object = itor->second;
00170                         LLXMLNodeList tasks_list;
00171                         object->getChildren("task", tasks_list, FALSE);
00172                         for (itor2 = tasks_list.begin(); itor2 != tasks_list.end(); ++itor2)
00173                         {
00174                                 LLXMLNode *task = itor2->second;
00175                                 LLXMLNodePtr temp_node;
00176                                 if (!task->getChild("root", temp_node, FALSE))
00177                                 {
00178                                         
00179                                         LLString task_name = "(unnamed object)";
00180                                         LLXMLNodePtr task_name_node;
00181                                         if (task->getChild("name", task_name_node, FALSE))
00182                                         {
00183                                                 task_name_node->getStringValue(1, &task_name);
00184                                         }
00185                                         {
00186                                                 LLString output_line;
00187                                                 char buffer[20];                
00188                                                 snprintf(buffer, sizeof(buffer), "%d", (S32)tasks_list.size()); 
00189                                                 output_line.append(buffer);
00190                                                 output_line.append(" prims");
00191 
00192                                                 LLSD row;
00193                                                 row["columns"][0]["value"] = "OBJECT";
00194                                                 row["columns"][0]["width"] = 60;
00195                                                 row["columns"][1]["value"] = output_line;
00196                                                 row["columns"][1]["width"] = 80;
00197                                                 row["columns"][2]["value"] = task_name;
00198                                                 row["enabled"] = false;
00199                                                 mImportList->addElement(row);
00200                                         }
00201                                         mImportList->setCanSelect(TRUE);
00202                                         mImportList->setAllowMultipleSelection(TRUE);
00203                                         object_file_read = true;
00204                                         object_count++;
00205                                         break;
00206                                 }
00207                         }
00208                 }
00209 
00210                 if (object_count > 0)
00211                 {
00212                         std::string::size_type pos = mFilenameAndPath.rfind(".");
00213                         if (pos != mFilenameAndPath.npos)
00214                         {
00215                                 mInventoryPath = mFilenameAndPath.substr(0, pos);
00216                         }
00217                         else
00218                         {
00219                                 mInventoryPath = mFilenameAndPath;
00220                         }
00221                         mInventoryPath.append("_inventory");
00222 
00223                         LLXMLNodeList image_list;
00224                         mObjectFile->findName("sl:image", image_list);
00225                         std::vector<LLString> unique_images;
00226                         std::vector<LLUUID> unique_ids;
00227                         std::vector<bool> image_changed;
00228                         for (itor = image_list.begin(); itor != image_list.end(); ++itor)
00229                         {
00230                                 LLXMLNode *image_node = itor->second;
00231                                 LLString image_id = image_node->getID();
00232 
00233                                 LLUUID image_uuid;
00234                                 image_node->getUUIDValue(1, &image_uuid);
00235 
00236                                 bool found_image = false;
00237                                 for (U32 image_num=0; image_num<unique_images.size(); ++image_num)
00238                                 {
00239                                         if (unique_images[image_num] == image_id)
00240                                         {
00241                                                 found_image = true;
00242                                                 continue;
00243                                         }
00244                                 }
00245                                 if (!found_image)
00246                                 {
00247                                         unique_images.push_back(image_id);
00248                                         unique_ids.push_back(image_uuid);
00249 
00250                                         LLString node_hash = "00000000000000000000000000000000";
00251                                         LLXMLNodePtr image_hash_node;
00252                                         if (image_node->getChild("checksum", image_hash_node))
00253                                         {
00254                                                 image_hash_node->getStringValue(1, &node_hash);
00255                                         }
00256 
00257                                         llinfos << "Node hash: " << node_hash << llendl;
00258 
00259                                         
00260                                         LLString image_path = mInventoryPath;
00261                                         image_path.append(gDirUtilp->getDirDelimiter());
00262                                         image_path.append(image_id);
00263                                         image_path.append(".tga");
00264 
00265                                         llinfos << "Getting hash for " << image_path << llendl;
00266 
00267                                         char md5_hash_string[33];       
00268                                         strcpy(md5_hash_string, "00000000000000000000000000000000");                    
00269                                         FILE* fCheck = LLFile::fopen(image_path.c_str(), "rb"); 
00270                                         if (fCheck)
00271                                         {
00272                                                 LLMD5 my_md5_hash(fCheck); 
00273                                                 my_md5_hash.hex_digest(md5_hash_string);
00274 
00275                                                 llinfos << "hash: " << md5_hash_string << llendl;
00276                                         }
00277 
00278                                         LoadPreviewImage(image_path, image_uuid);
00279 
00280                                         if (memcmp(md5_hash_string, node_hash.c_str(), 32) == 0)
00281                                         {
00282                                                 
00283                                                 image_changed.push_back(false);
00284                                         }
00285                                         else
00286                                         {
00287                                                 
00288                                                 image_changed.push_back(true);
00289                                         }
00290                                 }
00291                         }
00292                         for (U32 image_num=0; image_num<unique_images.size(); ++image_num)
00293                         {
00294                                 LLSD row;
00295                                 row["columns"][0]["value"] = "IMAGE";
00296                                 row["columns"][0]["width"] = 60;
00297                                 row["columns"][1]["value"] = image_changed[image_num]?"NEW":"NOT NEW";
00298                                 row["columns"][1]["width"] = 80;
00299                                 row["columns"][2]["value"] = unique_images[image_num];
00300                                 mImportList->addElement(row);
00301                                 mImportList->setCanSelect(TRUE);
00302                                 image_count++;
00303                         }
00304                 }
00305         }
00306 
00307         if (!object_file_read)
00308         {
00309                 mImportList->addSimpleItem("Error: Invalid object file.", ADD_BOTTOM, FALSE);
00310                 mImportList->setCanSelect(FALSE);
00311                 mOKBtn->setEnabled(FALSE);
00312         }
00313         else
00314         {
00315                 recalcCost();
00316         }
00317 
00318         return TRUE;
00319 }
00320 
00321 void LLFloaterImport::LoadPreviewImage(LLString image_path, LLUUID image_uuid)
00322 {
00323         LLPointer<LLImageRaw> raw_image = new LLImageRaw;
00324         LLPointer<LLImageTGA> tga_image = new LLImageTGA;
00325 
00326         if (!tga_image->load(image_path))
00327         {
00328                 return;
00329         }
00330         
00331         if (!tga_image->decode(raw_image))
00332         {
00333                 return;
00334         }
00335 
00336         if(     (tga_image->getComponents() != 3) &&
00337                 (tga_image->getComponents() != 4) )
00338         {
00339                 tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
00340                 return;
00341         }
00342 
00343         raw_image->biasedScaleToPowerOfTwo(256);
00344 
00345         mPreviewImages[image_uuid] = raw_image;
00346 }
00347 
00348 
00349 
00350 
00351 LLFloaterImport::~LLFloaterImport()
00352 {
00353         if (mGLName)
00354         {
00355                 glDeleteTextures(1, &mGLName );
00356         }
00357 }
00358 
00359 
00360 
00361 
00362 void LLFloaterImport::recalcCost()
00363 {
00364         
00365 
00366 
00367 
00368 
00369 
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389 }
00390 
00391 
00392 
00393 
00394 void LLFloaterImport::draw()
00395 {
00396         LLFloater::draw();
00397 
00398         LLRect PreviewImageRect;
00399         BOOL has_rect = childGetRect("dummy_preview", PreviewImageRect);
00400         
00401         if (mCurrentPreviewImage.notNull() && has_rect)
00402         {
00403                 gl_rect_2d_checkerboard(PreviewImageRect);
00404 
00405                 GLenum format_options[4] = { GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
00406                 GLenum format = format_options[mCurrentPreviewImage->getComponents()-1];
00407 
00408                 GLenum internal_format_options[4] = { GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8 };
00409                 GLenum internal_format = internal_format_options[mCurrentPreviewImage->getComponents()-1];
00410         
00411                 if (mGLName)
00412                 {
00413                         LLImageGL::bindExternalTexture( mGLName, 0, GL_TEXTURE_2D ); 
00414                 }
00415                 else
00416                 {
00417                         glGenTextures(1, &mGLName );
00418                         stop_glerror();
00419 
00420                         LLImageGL::bindExternalTexture( mGLName, 0, GL_TEXTURE_2D ); 
00421                         stop_glerror();
00422 
00423                         glTexImage2D(
00424                                 GL_TEXTURE_2D, 0, internal_format, 
00425                                 mCurrentPreviewImage->getWidth(), mCurrentPreviewImage->getHeight(),
00426                                 0, format, GL_UNSIGNED_BYTE, mCurrentPreviewImage->getData());
00427                         stop_glerror();
00428 
00429                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00430                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00431                         
00432                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00433                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00434                 }
00435 
00436                 glColor3f(1.f, 1.f, 1.f);
00437                 glBegin( GL_QUADS );
00438                 {
00439                         glTexCoord2f(0, 1);
00440                         glVertex2i(PreviewImageRect.mLeft, PreviewImageRect.mTop);
00441                         glTexCoord2f(0, 0);
00442                         glVertex2i(PreviewImageRect.mLeft, PreviewImageRect.mBottom);
00443                         glTexCoord2f(1, 0);
00444                         glVertex2i(PreviewImageRect.mRight, PreviewImageRect.mBottom);
00445                         glTexCoord2f(1, 1);
00446                         glVertex2i(PreviewImageRect.mRight, PreviewImageRect.mTop);
00447                 }
00448                 glEnd();
00449 
00450                 LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
00451 
00452                 stop_glerror();
00453         }
00454 }
00455 
00456 
00457 void LLFloaterImport::finishImport(ImportAssetInfo *info)
00458 {
00459         
00460         
00461         
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511 
00512 
00513 }
00514 
00515 
00516 void LLFloaterImport::asset_uploaded_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status)
00517 {
00518         llinfos << "LLFloaterImport: Finished uploading image." << llendl;
00519         LLResourceData *resource_data = (LLResourceData*)user_data;
00520         ImportAssetInfo *info = (ImportAssetInfo*)resource_data->mUserData;
00521 
00522         info->NewImageIDList.push_back(resource_data->mAssetInfo.mUuid.asString());
00523 
00524         LLUploadDialog::modalUploadFinished();
00525         if (info->ImageFileQueue.size() == 0)
00526         {
00527                 finishImport(info);
00528         }
00529         else
00530         {
00531                 
00532                 LLString current_image = info->ImageFileQueue[0].c_str();
00533                 info->ImageFileQueue.erase(info->ImageFileQueue.begin());
00534 
00535                 upload_new_resource(current_image, info->Name, 
00536                         info->Desc, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, 
00537                         PERM_NONE, LLString::null, asset_uploaded_callback, info);
00538         }
00539 }
00540 
00541 
00542 
00543 
00544 void LLFloaterImport::onBtnOK(void*userdata)
00545 {
00546         LLFloaterImport *fp =(LLFloaterImport*)userdata;
00547 
00548         ImportAssetInfo *asset_info = new ImportAssetInfo();
00549         asset_info->Name = fp->mNameEditor->getText();
00550         asset_info->Desc = fp->mDescEditor->getText();
00551         asset_info->FilenameAndPath = fp->mFilenameAndPath;
00552         asset_info->SourcePath = fp->mInventoryPath;
00553 
00554         std::vector<LLScrollListItem*> items = fp->mImportList->getAllSelected();
00555         std::vector<LLScrollListItem*>::iterator itor;
00556         if (items.size() > 0)
00557         {
00558                 for (itor = items.begin(); itor != items.end(); ++itor)
00559                 {
00560                         LLUUID id = (*itor)->getUUID();
00561 
00562                         
00563                         LLString *image_id = (LLString *)(*itor)->getUserdata();
00564                         if (image_id)
00565                         {
00566                                 asset_info->OldImageIDList.push_back(id.asString());
00567                                 LLString image_file = fp->mInventoryPath;
00568                                 image_file.append(gDirUtilp->getDirDelimiter());
00569                                 image_file.append(*image_id);
00570                                 image_file.append(".tga");
00571                                 llinfos << "Uploading image " << image_file << "..." << llendl;
00572                                 asset_info->ImageFileQueue.push_back(image_file);
00573                         }
00574                 }
00575                 if (asset_info->ImageFileQueue.size() == 0)
00576                 {
00577                         finishImport(asset_info);
00578                 }
00579                 else
00580                 {
00581                         
00582                         LLString current_image = asset_info->ImageFileQueue[0].c_str();
00583                         asset_info->ImageFileQueue.erase(asset_info->ImageFileQueue.begin());
00584 
00585                         upload_new_resource(current_image, asset_info->Name, 
00586                                 asset_info->Desc, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, 
00587                                 PERM_NONE, LLString::null, asset_uploaded_callback, asset_info);
00588                 }
00589         }
00590         else
00591         {
00592                 finishImport(asset_info);
00593         }
00594 
00595         fp->close(false);
00596 }
00597 
00598 
00599 
00600 
00601 void LLFloaterImport::onBtnCancel(void*userdata)
00602 {
00603         LLFloaterImport *fp =(LLFloaterImport*)userdata;
00604         fp->close(false);
00605 }
00606 
00607 
00608 
00609 
00610 
00611 BOOL LLFloaterImport::handleMouseDown(S32 x, S32 y, MASK mask)
00612 {
00613         BOOL ret = LLFloater::handleMouseDown(x, y, mask);
00614         recalcCost();
00615 
00616         LLUUID current_preview_uuid;
00617         LLString current_preview_name = "none";
00618 
00619         LLScrollListItem *item;
00620         
00621         
00622         item = mImportList->getLastSelectedItem();
00623         if (item)
00624         {
00625                 current_preview_uuid = item->getUUID();
00626                 current_preview_name = item->getColumn(2)->getText();
00627         }
00628         else
00629         {
00630                 
00631                 std::vector<LLScrollListItem*> items = mImportList->getAllSelected();
00632                 std::vector<LLScrollListItem*>::iterator itor;
00633                 for (itor = items.begin(); itor != items.end(); ++itor)
00634                 {
00635                         if (current_preview_uuid.isNull())
00636                         {
00637                                 current_preview_uuid = (*itor)->getUUID();
00638                                 current_preview_name = (*itor)->getColumn(2)->getText();
00639                         }
00640                         else
00641                         {
00642                                 
00643                                 current_preview_uuid.setNull();
00644                                 current_preview_name = "none";
00645                                 break;
00646                         }
00647                 }
00648         }
00649 
00650         mCurrentPreviewImage = NULL;
00651         if (current_preview_uuid.notNull())
00652         {
00653                 image_map_t::iterator itor;
00654                 itor = mPreviewImages.find(current_preview_uuid);
00655                 if (itor != mPreviewImages.end())
00656                 {
00657                         mCurrentPreviewImage = itor->second;
00658                         if (mGLName)
00659                         {
00660                                 glDeleteTextures(1, &mGLName );
00661                         }
00662                         mGLName = 0;
00663                 }
00664         }
00665         LLString label_text = "Image Preview: ";
00666         label_text.append(current_preview_name);
00667         mImageLabel->setText(label_text);
00668 
00669         return ret;
00670 }