llpanelclassified.cpp

Go to the documentation of this file.
00001 
00032 // Display of a classified used both for the global view in the
00033 // Find directory, and also for each individual user's classified in their
00034 // profile.
00035 
00036 #include "llviewerprecompiledheaders.h"
00037 
00038 #include "llpanelclassified.h"
00039 
00040 #include "lldir.h"
00041 #include "lldispatcher.h"
00042 #include "llparcel.h"
00043 #include "message.h"
00044 
00045 #include "llagent.h"
00046 #include "llalertdialog.h"
00047 #include "llbutton.h"
00048 #include "llcheckboxctrl.h"
00049 #include "llclassifiedflags.h"
00050 #include "llclassifiedstatsresponder.h"
00051 #include "llviewercontrol.h"
00052 #include "lllineeditor.h"
00053 #include "llfloateravatarinfo.h"
00054 #include "llfloaterclassified.h"
00055 #include "lltabcontainervertical.h"
00056 #include "lltextbox.h"
00057 #include "llcombobox.h"
00058 #include "llviewertexteditor.h"
00059 #include "lltexturectrl.h"
00060 #include "lluiconstants.h"
00061 #include "llvieweruictrlfactory.h"
00062 #include "llviewerparcelmgr.h"
00063 #include "llviewerwindow.h"
00064 #include "llworldmap.h"
00065 #include "llfloaterworldmap.h"
00066 #include "llviewergenericmessage.h"     // send_generic_message
00067 #include "llviewerregion.h"
00068 #include "llviewerwindow.h"     // for window width, height
00069 #include "viewer.h"     // app_abort_quit()
00070 
00071 const S32 MINIMUM_PRICE_FOR_LISTING = 50;       // L$
00072 
00073 // "classifiedclickthrough"
00074 // strings[0] = classified_id
00075 // strings[1] = teleport_clicks
00076 // strings[2] = map_clicks
00077 // strings[3] = profile_clicks
00078 class LLDispatchClassifiedClickThrough : public LLDispatchHandler
00079 {
00080 public:
00081         virtual bool operator()(
00082                 const LLDispatcher* dispatcher,
00083                 const std::string& key,
00084                 const LLUUID& invoice,
00085                 const sparam_t& strings)
00086         {
00087                 if (strings.size() != 4) return false;
00088                 LLUUID classified_id(strings[0]);
00089                 S32 teleport_clicks = atoi(strings[1].c_str());
00090                 S32 map_clicks = atoi(strings[2].c_str());
00091                 S32 profile_clicks = atoi(strings[3].c_str());
00092                 LLPanelClassified::setClickThrough(classified_id, teleport_clicks,
00093                                                                                    map_clicks,
00094                                                                                    profile_clicks,
00095                                                                                    false);
00096                 return true;
00097         }
00098 };
00099 
00100 static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
00101 
00102 //static
00103 std::list<LLPanelClassified*> LLPanelClassified::sAllPanels;
00104 
00105 LLPanelClassified::LLPanelClassified(BOOL in_finder, bool from_search)
00106 :       LLPanel("Classified Panel"),
00107         mInFinder(in_finder),
00108         mFromSearch(from_search),
00109         mDirty(false),
00110         mForceClose(false),
00111         mLocationChanged(false),
00112         mClassifiedID(),
00113         mCreatorID(),
00114         mPriceForListing(0),
00115         mDataRequested(FALSE),
00116         mPaidFor(FALSE),
00117         mPosGlobal(),
00118         mSnapshotCtrl(NULL),
00119         mNameEditor(NULL),
00120         mDescEditor(NULL),
00121         mLocationEditor(NULL),
00122         mCategoryCombo(NULL),
00123         mMatureCheck(NULL),
00124         mAutoRenewCheck(NULL),
00125         mUpdateBtn(NULL),
00126         mTeleportBtn(NULL),
00127         mMapBtn(NULL),
00128         mProfileBtn(NULL),
00129         mInfoText(NULL),
00130         mSetBtn(NULL),
00131         mClickThroughText(NULL),
00132         mTeleportClicksOld(0),
00133         mMapClicksOld(0),
00134         mProfileClicksOld(0),
00135         mTeleportClicksNew(0),
00136         mMapClicksNew(0),
00137         mProfileClicksNew(0)
00138 
00139 {
00140     sAllPanels.push_back(this);
00141 
00142         std::string classified_def_file;
00143         if (mInFinder)
00144         {
00145                 gUICtrlFactory->buildPanel(this, "panel_classified.xml");
00146         }
00147         else
00148         {
00149                 gUICtrlFactory->buildPanel(this, "panel_avatar_classified.xml");
00150         }
00151 
00152         // Register dispatcher
00153         gGenericDispatcher.addHandler("classifiedclickthrough", 
00154                                                                   &sClassifiedClickThrough);
00155 }
00156 
00157 
00158 LLPanelClassified::~LLPanelClassified()
00159 {
00160     sAllPanels.remove(this);
00161 }
00162 
00163 
00164 void LLPanelClassified::reset()
00165 {
00166         mClassifiedID.setNull();
00167         mCreatorID.setNull();
00168         mParcelID.setNull();
00169 
00170         // Don't request data, this isn't valid
00171         mDataRequested = TRUE;
00172 
00173         mDirty = false;
00174         mPaidFor = FALSE;
00175 
00176         mPosGlobal.clearVec();
00177 
00178         clearCtrls();
00179 }
00180 
00181 
00182 BOOL LLPanelClassified::postBuild()
00183 {
00184     mSnapshotCtrl = LLViewerUICtrlFactory::getTexturePickerByName(this, "snapshot_ctrl");
00185         mSnapshotCtrl->setCommitCallback(onCommitAny);
00186         mSnapshotCtrl->setCallbackUserData(this);
00187         mSnapshotSize = mSnapshotCtrl->getRect();
00188 
00189     mNameEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "given_name_editor");
00190         mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN);
00191         mNameEditor->setCommitOnFocusLost(TRUE);
00192         mNameEditor->setFocusReceivedCallback(onFocusReceived);
00193         mNameEditor->setCommitCallback(onCommitAny);
00194         mNameEditor->setCallbackUserData(this);
00195         mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII );
00196 
00197     mDescEditor = LLUICtrlFactory::getTextEditorByName(this, "desc_editor");
00198         mDescEditor->setCommitOnFocusLost(TRUE);
00199         mDescEditor->setFocusReceivedCallback(onFocusReceived);
00200         mDescEditor->setCommitCallback(onCommitAny);
00201         mDescEditor->setCallbackUserData(this);
00202         mDescEditor->setTabToNextField(TRUE);
00203 
00204     mLocationEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "location_editor");
00205 
00206     mSetBtn = LLViewerUICtrlFactory::getButtonByName(this, "set_location_btn");
00207     mSetBtn->setClickedCallback(onClickSet);
00208     mSetBtn->setCallbackUserData(this);
00209 
00210     mTeleportBtn = LLViewerUICtrlFactory::getButtonByName(this, "classified_teleport_btn");
00211     mTeleportBtn->setClickedCallback(onClickTeleport);
00212     mTeleportBtn->setCallbackUserData(this);
00213 
00214     mMapBtn = LLViewerUICtrlFactory::getButtonByName(this, "classified_map_btn");
00215     mMapBtn->setClickedCallback(onClickMap);
00216     mMapBtn->setCallbackUserData(this);
00217 
00218         if(mInFinder)
00219         {
00220                 mProfileBtn  = LLViewerUICtrlFactory::getButtonByName(this, "classified_profile_btn");
00221                 mProfileBtn->setClickedCallback(onClickProfile);
00222                 mProfileBtn->setCallbackUserData(this);
00223         }
00224 
00225         mCategoryCombo = LLViewerUICtrlFactory::getComboBoxByName(this, "classified_category_combo");
00226         LLClassifiedInfo::cat_map::iterator iter;
00227         for (iter = LLClassifiedInfo::sCategories.begin();
00228                 iter != LLClassifiedInfo::sCategories.end();
00229                 iter++)
00230         {
00231                 mCategoryCombo->add(iter->second, (void *)((intptr_t)iter->first), ADD_BOTTOM);
00232         }
00233         mCategoryCombo->setCurrentByIndex(0);
00234         mCategoryCombo->setCommitCallback(onCommitAny);
00235         mCategoryCombo->setCallbackUserData(this);
00236 
00237         mMatureCheck = LLViewerUICtrlFactory::getCheckBoxByName(this, "classified_mature_check");
00238         mMatureCheck->setCommitCallback(onCommitAny);
00239         mMatureCheck->setCallbackUserData(this);
00240         if (gAgent.isTeen())
00241         {
00242                 // Teens don't get to set mature flag. JC
00243                 mMatureCheck->setVisible(FALSE);
00244         }
00245 
00246         if (!mInFinder)
00247         {
00248                 mAutoRenewCheck = LLUICtrlFactory::getCheckBoxByName(this, "auto_renew_check");
00249                 mAutoRenewCheck->setCommitCallback(onCommitAny);
00250                 mAutoRenewCheck->setCallbackUserData(this);
00251         }
00252 
00253         mUpdateBtn = LLUICtrlFactory::getButtonByName(this, "classified_update_btn");
00254     mUpdateBtn->setClickedCallback(onClickUpdate);
00255     mUpdateBtn->setCallbackUserData(this);
00256 
00257         if (!mInFinder)
00258         {
00259                 mClickThroughText = LLUICtrlFactory::getTextBoxByName(this, "click_through_text");
00260         }
00261         
00262     return TRUE;
00263 }
00264 
00265 BOOL LLPanelClassified::titleIsValid()
00266 {
00267         // Disallow leading spaces, punctuation, etc. that screw up
00268         // sort order.
00269         const LLString& name = mNameEditor->getText();
00270         if (name.empty())
00271         {
00272                 gViewerWindow->alertXml("BlankClassifiedName");
00273                 return FALSE;
00274         }
00275         if (!isalnum(name[0]))
00276         {
00277                 gViewerWindow->alertXml("ClassifiedMustBeAlphanumeric");
00278                 return FALSE;
00279         }
00280 
00281         return TRUE;
00282 }
00283 
00284 void LLPanelClassified::apply()
00285 {
00286         // Apply is used for automatically saving results, so only
00287         // do that if there is a difference, and this is a save not create.
00288         if (checkDirty() && mPaidFor)
00289         {
00290                 sendClassifiedInfoUpdate();
00291         }
00292 }
00293 
00294 
00295 // static
00296 void LLPanelClassified::saveCallback(S32 option, void* data)
00297 {
00298         LLPanelClassified* self = (LLPanelClassified*)data;
00299         switch(option)
00300         {
00301                 case 0: // Save
00302                         self->sendClassifiedInfoUpdate();
00303                         // fall through to close
00304 
00305                 case 1: // Don't Save
00306                         {
00307                                 self->mForceClose = true;
00308                                 // Close containing floater
00309                                 LLView* view = self;
00310                                 while (view)
00311                                 {
00312                                         if (view->getWidgetType() == WIDGET_TYPE_FLOATER)
00313                                         {
00314                                                 LLFloater* f = (LLFloater*)view;
00315                                                 f->close();
00316                                                 break;
00317                                         }
00318                                         view = view->getParent();
00319                                 }
00320                         }
00321                         break;
00322 
00323                 case 2: // Cancel
00324                 default:
00325                         app_abort_quit();
00326                         break;
00327         }
00328 }
00329 
00330 BOOL LLPanelClassified::canClose()
00331 {
00332         if (mForceClose || !checkDirty()) 
00333                 return TRUE;
00334 
00335         LLString::format_map_t args;
00336         args["[NAME]"] = mNameEditor->getText();
00337         LLAlertDialog::showXml("ClassifiedSave", args, saveCallback, this);
00338         return FALSE;
00339 }
00340 
00341 // Fill in some reasonable defaults for a new classified.
00342 void LLPanelClassified::initNewClassified()
00343 {
00344         // TODO:  Don't generate this on the client.
00345         mClassifiedID.generate();
00346 
00347         mCreatorID = gAgent.getID();
00348 
00349         mPosGlobal = gAgent.getPositionGlobal();
00350 
00351         mPaidFor = FALSE;
00352 
00353         // Try to fill in the current parcel
00354         LLParcel* parcel = gParcelMgr->getAgentParcel();
00355         if (parcel)
00356         {
00357                 mNameEditor->setText(parcel->getName());
00358                 //mDescEditor->setText(parcel->getDesc());
00359                 mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID());
00360                 //mPriceEditor->setText("0");
00361                 mCategoryCombo->setCurrentByIndex(0);
00362         }
00363 
00364         // default new classifieds to publish
00365         //mEnabledCheck->set(TRUE);
00366 
00367         // delay commit until user hits save
00368         // sendClassifiedInfoUpdate();
00369 
00370         mUpdateBtn->setLabel(childGetText("publish_txt"));
00371 }
00372 
00373 
00374 void LLPanelClassified::setClassifiedID(const LLUUID& id)
00375 {
00376         mClassifiedID = id;
00377 }
00378 
00379 //static
00380 void LLPanelClassified::setClickThrough(const LLUUID& classified_id,
00381                                                                                 S32 teleport,
00382                                                                                 S32 map,
00383                                                                                 S32 profile,
00384                                                                                 bool from_new_table)
00385 {
00386         for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
00387         {
00388                 LLPanelClassified* self = *iter;
00389                 // For top picks, must match pick id
00390                 if (self->mClassifiedID != classified_id)
00391                 {
00392                         continue;
00393                 }
00394 
00395                 // We need to check to see if the data came from the new stat_table 
00396                 // or the old classified table. We also need to cache the data from 
00397                 // the two separate sources so as to display the aggregate totals.
00398 
00399                 if (from_new_table)
00400                 {
00401                         self->mTeleportClicksNew = teleport;
00402                         self->mMapClicksNew = map;
00403                         self->mProfileClicksNew = profile;
00404                 }
00405                 else
00406                 {
00407                         self->mTeleportClicksOld = teleport;
00408                         self->mMapClicksOld = map;
00409                         self->mProfileClicksOld = profile;
00410                 }
00411 
00412                 if (self->mClickThroughText)
00413                 {
00414                         std::string msg = llformat("Clicks: %d teleport, %d map, %d profile",
00415                                                                         self->mTeleportClicksNew + self->mTeleportClicksOld,
00416                                                                         self->mMapClicksNew + self->mMapClicksOld,
00417                                                                         self->mProfileClicksNew + self->mProfileClicksOld);
00418                         self->mClickThroughText->setText(msg);
00419                 }
00420         }
00421 }
00422 
00423 // Schedules the panel to request data
00424 // from the server next time it is drawn.
00425 void LLPanelClassified::markForServerRequest()
00426 {
00427         mDataRequested = FALSE;
00428 }
00429 
00430 
00431 std::string LLPanelClassified::getClassifiedName()
00432 {
00433         return mNameEditor->getText();
00434 }
00435 
00436 
00437 void LLPanelClassified::sendClassifiedInfoRequest()
00438 {
00439     LLMessageSystem *msg = gMessageSystem;
00440 
00441         if (mClassifiedID != mRequestedID)
00442         {
00443                 msg->newMessageFast(_PREHASH_ClassifiedInfoRequest);
00444                 msg->nextBlockFast(_PREHASH_AgentData);
00445                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
00446                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
00447                 msg->nextBlockFast(_PREHASH_Data);
00448                 msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID);
00449                 gAgent.sendReliableMessage();
00450 
00451                 mDataRequested = TRUE;
00452                 mRequestedID = mClassifiedID;
00453 
00454                 // While we're at it let's get the stats from the new table if that
00455                 // capability exists.
00456                 std::string url = gAgent.getRegion()->getCapability("SearchStatRequest");
00457                 LLSD body;
00458                 body["classified_id"] = mClassifiedID;
00459 
00460                 if (!url.empty())
00461                 {
00462                         llinfos << "Classified stat request via capability" << llendl;
00463                         LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(this->getHandle(), mClassifiedID));
00464                 }
00465         }
00466 }
00467 
00468 
00469 void LLPanelClassified::sendClassifiedInfoUpdate()
00470 {
00471         // If we don't have a classified id yet, we'll need to generate one,
00472         // otherwise we'll keep overwriting classified_id 00000 in the database.
00473         if (mClassifiedID.isNull())
00474         {
00475                 // TODO:  Don't do this on the client.
00476                 mClassifiedID.generate();
00477         }
00478 
00479         LLMessageSystem* msg = gMessageSystem;
00480 
00481         msg->newMessageFast(_PREHASH_ClassifiedInfoUpdate);
00482         msg->nextBlockFast(_PREHASH_AgentData);
00483         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00484         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00485         msg->nextBlockFast(_PREHASH_Data);
00486         msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID);
00487         // TODO: fix this
00488         U32 category = mCategoryCombo->getCurrentIndex() + 1;
00489         msg->addU32Fast(_PREHASH_Category, category);
00490         msg->addStringFast(_PREHASH_Name, mNameEditor->getText());
00491         msg->addStringFast(_PREHASH_Desc, mDescEditor->getText());
00492 
00493         // fills in on simulator if null
00494         msg->addUUIDFast(_PREHASH_ParcelID, mParcelID);
00495         // fills in on simulator if null
00496         msg->addU32Fast(_PREHASH_ParentEstate, 0);
00497         msg->addUUIDFast(_PREHASH_SnapshotID, mSnapshotCtrl->getImageAssetID());
00498         msg->addVector3dFast(_PREHASH_PosGlobal, mPosGlobal);
00499         BOOL mature = mMatureCheck->get();
00500         // Classifieds are always enabled/published 11/2005 JC
00501         //BOOL enabled = mEnabledCheck->get();
00502         BOOL auto_renew = FALSE;
00503         if (mAutoRenewCheck) 
00504         {
00505                 auto_renew = mAutoRenewCheck->get();
00506         }
00507         U8 flags = pack_classified_flags(mature, auto_renew);
00508         msg->addU8Fast(_PREHASH_ClassifiedFlags, flags);
00509         msg->addS32("PriceForListing", mPriceForListing);
00510         gAgent.sendReliableMessage();
00511 
00512         mDirty = false;
00513 }
00514 
00515 
00516 //static
00517 void LLPanelClassified::processClassifiedInfoReply(LLMessageSystem *msg, void **)
00518 {
00519         lldebugs << "processClassifiedInfoReply()" << llendl;
00520     // Extract the agent id and verify the message is for this
00521     // client.
00522     LLUUID agent_id;
00523     msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
00524     if (agent_id != gAgent.getID())
00525     {
00526         llwarns << "Agent ID mismatch in processClassifiedInfoReply"
00527             << llendl;
00528                 return;
00529     }
00530 
00531     LLUUID classified_id;
00532     msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id);
00533 
00534     LLUUID creator_id;
00535     msg->getUUIDFast(_PREHASH_Data, _PREHASH_CreatorID, creator_id);
00536 
00537     LLUUID parcel_id;
00538     msg->getUUIDFast(_PREHASH_Data, _PREHASH_ParcelID, parcel_id);
00539 
00540         char name[DB_PARCEL_NAME_SIZE];         /*Flawfinder: ignore*/
00541         msg->getStringFast(_PREHASH_Data, _PREHASH_Name, DB_PARCEL_NAME_SIZE, name);
00542 
00543         char desc[DB_PICK_DESC_SIZE];           /*Flawfinder: ignore*/
00544         msg->getStringFast(_PREHASH_Data, _PREHASH_Desc, DB_PICK_DESC_SIZE, desc);
00545 
00546         LLUUID snapshot_id;
00547         msg->getUUIDFast(_PREHASH_Data, _PREHASH_SnapshotID, snapshot_id);
00548 
00549     // "Location text" is actually the original
00550     // name that owner gave the parcel, and the location.
00551         char buffer[256];               /*Flawfinder: ignore*/
00552     LLString location_text;
00553 
00554     msg->getStringFast(_PREHASH_Data, _PREHASH_ParcelName, 256, buffer);
00555         if (buffer[0] != '\0')
00556         {
00557                 location_text.assign(buffer);
00558                 location_text.append(", ");
00559         }
00560         else
00561         {
00562                 location_text.assign("");
00563         }
00564 
00565         char sim_name[256];             /*Flawfinder: ignore*/
00566         msg->getStringFast(_PREHASH_Data, _PREHASH_SimName, 256, sim_name);
00567 
00568         LLVector3d pos_global;
00569         msg->getVector3dFast(_PREHASH_Data, _PREHASH_PosGlobal, pos_global);
00570 
00571     S32 region_x = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
00572     S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
00573         S32 region_z = llround((F32)pos_global.mdV[VZ]);
00574    
00575     snprintf(buffer, sizeof(buffer), "%s (%d, %d, %d)", sim_name, region_x, region_y, region_z);                        /* Flawfinder: ignore */
00576     location_text.append(buffer);
00577 
00578         U8 flags;
00579         msg->getU8Fast(_PREHASH_Data, _PREHASH_ClassifiedFlags, flags);
00580         //BOOL enabled = is_cf_enabled(flags);
00581         bool mature = is_cf_mature(flags);
00582         bool auto_renew = is_cf_auto_renew(flags);
00583 
00584         U32 date = 0;
00585         msg->getU32Fast(_PREHASH_Data, _PREHASH_CreationDate, date);
00586         time_t tim = date;
00587         tm *now=localtime(&tim);
00588 
00589         // future use
00590         U32 expiration_date = 0;
00591         msg->getU32("Data", "ExpirationDate", expiration_date);
00592 
00593         U32 category = 0;
00594         msg->getU32Fast(_PREHASH_Data, _PREHASH_Category, category);
00595 
00596         S32 price_for_listing = 0;
00597         msg->getS32("Data", "PriceForListing", price_for_listing);
00598 
00599     // Look up the panel to fill in
00600         for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
00601         {
00602                 LLPanelClassified* self = *iter;
00603                 // For top picks, must match pick id
00604                 if (self->mClassifiedID != classified_id)
00605                 {
00606                         continue;
00607                 }
00608 
00609         // Found the panel, now fill in the information
00610                 self->mClassifiedID = classified_id;
00611                 self->mCreatorID = creator_id;
00612                 self->mParcelID = parcel_id;
00613                 self->mPriceForListing = price_for_listing;
00614                 self->mSimName.assign(sim_name);
00615                 self->mPosGlobal = pos_global;
00616 
00617                 // Update UI controls
00618         self->mNameEditor->setText(LLString(name));
00619         self->mDescEditor->setText(LLString(desc));
00620         self->mSnapshotCtrl->setImageAssetID(snapshot_id);
00621         self->mLocationEditor->setText(location_text);
00622                 self->mLocationChanged = false;
00623 
00624                 self->mCategoryCombo->setCurrentByIndex(category - 1);
00625                 self->mMatureCheck->set(mature);
00626                 if (self->mAutoRenewCheck)
00627                 {
00628                         self->mAutoRenewCheck->set(auto_renew);
00629                 }
00630 
00631                 LLString datestr = llformat("%02d/%02d/%d", now->tm_mon+1, now->tm_mday, now->tm_year+1900);
00632                 self->childSetTextArg("ad_placed_paid", "[DATE]", datestr);
00633                 self->childSetTextArg("ad_placed_paid", "[AMT]", llformat("%d", price_for_listing));            
00634                 self->childSetText("classified_info_text", self->childGetValue("ad_placed_paid").asString());
00635 
00636                 // If we got data from the database, we know the listing is paid for.
00637                 self->mPaidFor = TRUE;
00638 
00639                 self->mUpdateBtn->setLabel(self->childGetText("update_txt"));
00640     }
00641 }
00642 
00643 void LLPanelClassified::draw()
00644 {
00645         if (getVisible())
00646         {
00647                 refresh();
00648 
00649                 LLPanel::draw();
00650         }
00651 }
00652 
00653 
00654 void LLPanelClassified::refresh()
00655 {
00656         if (!mDataRequested)
00657         {
00658                 sendClassifiedInfoRequest();
00659         }
00660 
00661     // Check for god mode
00662     BOOL godlike = gAgent.isGodlike();
00663         BOOL is_self = (gAgent.getID() == mCreatorID);
00664 
00665     // Set button visibility/enablement appropriately
00666         if (mInFinder)
00667         {
00668 
00669                 // End user doesn't ned to see price twice, or date posted.
00670 
00671                 mSnapshotCtrl->setEnabled(godlike);
00672                 if(godlike)
00673                 {
00674                         //make it smaller, so text is more legible
00675                         mSnapshotCtrl->setRect(LLRect(20, 375, 320, 175));
00676                         
00677                 }
00678                 else
00679                 {
00680                         mSnapshotCtrl->setRect(mSnapshotSize);
00681                         //normal
00682                 }
00683                 mNameEditor->setEnabled(godlike);
00684                 mDescEditor->setEnabled(godlike);
00685                 mCategoryCombo->setEnabled(godlike);
00686                 mCategoryCombo->setVisible(godlike);
00687 
00688                 //mEnabledCheck->setVisible(godlike);
00689                 //mEnabledCheck->setEnabled(godlike);
00690 
00691                 mMatureCheck->setEnabled(godlike);
00692                 mMatureCheck->setVisible(godlike);
00693 
00694                 // Jesse (who is the only one who uses this, as far as we can tell
00695                 // Says that he does not want a set location button - he has used it
00696                 // accidently in the past.
00697                 mSetBtn->setVisible(FALSE);
00698                 mSetBtn->setEnabled(FALSE);
00699 
00700                 mUpdateBtn->setEnabled(godlike);
00701                 mUpdateBtn->setVisible(godlike);
00702         }
00703         else
00704         {
00705                 mSnapshotCtrl->setEnabled(is_self);
00706                 mNameEditor->setEnabled(is_self);
00707                 mDescEditor->setEnabled(is_self);
00708                 //mPriceEditor->setEnabled(is_self);
00709                 mCategoryCombo->setEnabled(is_self);
00710 
00711                 //mEnabledCheck->setVisible(FALSE);
00712                 //mEnabledCheck->setEnabled(is_self);
00713                 mMatureCheck->setEnabled(is_self);
00714 
00715                 if (mAutoRenewCheck)
00716                 {
00717                         mAutoRenewCheck->setEnabled(is_self);
00718                         mAutoRenewCheck->setVisible(is_self);
00719                 }
00720                 
00721                 mClickThroughText->setEnabled(is_self);
00722                 mClickThroughText->setVisible(is_self);
00723 
00724                 mSetBtn->setVisible(is_self);
00725                 mSetBtn->setEnabled(is_self);
00726 
00727                 mUpdateBtn->setEnabled(is_self && checkDirty());
00728                 mUpdateBtn->setVisible(is_self);
00729         }
00730 }
00731 
00732 // static
00733 void LLPanelClassified::onClickUpdate(void* data)
00734 {
00735         LLPanelClassified* self = (LLPanelClassified*)data;
00736 
00737         if(self == NULL) return;
00738 
00739         // Disallow leading spaces, punctuation, etc. that screw up
00740         // sort order.
00741         if ( ! self->titleIsValid() )
00742         {
00743                 return;
00744         };
00745 
00746         // if already paid for, just do the update
00747         if (self->mPaidFor)
00748         {
00749                 callbackConfirmPublish(0, self);
00750         }
00751         else
00752         {
00753                 // Ask the user how much they want to pay
00754                 LLFloaterPriceForListing::show( callbackGotPriceForListing, self );
00755         }
00756 }
00757 
00758 // static
00759 void LLPanelClassified::callbackGotPriceForListing(S32 option, LLString text, void* data)
00760 {
00761         LLPanelClassified* self = (LLPanelClassified*)data;
00762 
00763         // Only do something if user hits publish
00764         if (option != 0) return;
00765 
00766         S32 price_for_listing = strtol(text.c_str(), NULL, 10);
00767         if (price_for_listing < MINIMUM_PRICE_FOR_LISTING)
00768         {
00769                 LLString::format_map_t args;
00770                 LLString price_text = llformat("%d", MINIMUM_PRICE_FOR_LISTING);
00771                 args["[MIN_PRICE]"] = price_text;
00772                         
00773                 gViewerWindow->alertXml("MinClassifiedPrice", args);
00774                 return;
00775         }
00776 
00777         // price is acceptable, put it in the dialog for later read by 
00778         // update send
00779         self->mPriceForListing = price_for_listing;
00780 
00781         LLString::format_map_t args;
00782         args["[AMOUNT]"] = llformat("%d", price_for_listing);
00783         gViewerWindow->alertXml("PublishClassified", args, &callbackConfirmPublish, self);
00784 
00785 }
00786 
00787 
00788 // invoked from callbackConfirmPublish
00789 void LLPanelClassified::confirmPublish(S32 option)
00790 {
00791         // Option 0 = publish
00792         if (option != 0) return;
00793 
00794         sendClassifiedInfoUpdate();
00795 
00796         // Big hack - assume that top picks are always in a browser,
00797         // and non-finder-classifieds are always in a tab container.
00798         if (mInFinder)
00799         {
00800                 // TODO: enable this
00801                 //LLPanelDirClassifieds* panel = (LLPanelDirClassifieds*)getParent();
00802                 //panel->renameClassified(mClassifiedID, mNameEditor->getText().c_str());
00803         }
00804         else
00805         {
00806                 LLTabContainerVertical* tab = (LLTabContainerVertical*)getParent();
00807                 tab->setCurrentTabName(mNameEditor->getText());
00808         }
00809 
00810         // Tell all the widgets to reset their dirty state since the ad was just saved
00811         mSnapshotCtrl->resetDirty();
00812         mNameEditor->resetDirty();
00813         mDescEditor->resetDirty();
00814         mLocationEditor->resetDirty();
00815         mLocationChanged = false;
00816         mCategoryCombo->resetDirty();
00817         mMatureCheck->resetDirty();
00818         if (mAutoRenewCheck)
00819         {
00820                 mAutoRenewCheck->resetDirty();
00821         }
00822 }
00823 
00824 // static
00825 void LLPanelClassified::callbackConfirmPublish(S32 option, void* data)
00826 {
00827         LLPanelClassified* self = (LLPanelClassified*)data;
00828         self->confirmPublish(option);
00829 }
00830 
00831 // static
00832 void LLPanelClassified::onClickTeleport(void* data)
00833 {
00834     LLPanelClassified* self = (LLPanelClassified*)data;
00835 
00836     if (!self->mPosGlobal.isExactlyZero())
00837     {
00838         gAgent.teleportViaLocation(self->mPosGlobal);
00839         gFloaterWorldMap->trackLocation(self->mPosGlobal);
00840 
00841                 self->sendClassifiedClickMessage("teleport");
00842     }
00843 }
00844 
00845 
00846 // static
00847 void LLPanelClassified::onClickMap(void* data)
00848 {
00849         LLPanelClassified* self = (LLPanelClassified*)data;
00850         gFloaterWorldMap->trackLocation(self->mPosGlobal);
00851         LLFloaterWorldMap::show(NULL, TRUE);
00852 
00853         self->sendClassifiedClickMessage("map");
00854 }
00855 
00856 // static
00857 void LLPanelClassified::onClickProfile(void* data)
00858 {
00859         LLPanelClassified* self = (LLPanelClassified*)data;
00860         LLFloaterAvatarInfo::showFromDirectory(self->mCreatorID);
00861         self->sendClassifiedClickMessage("profile");
00862 }
00863 
00864 // static
00865 /*
00866 void LLPanelClassified::onClickLandmark(void* data)
00867 {
00868     LLPanelClassified* self = (LLPanelClassified*)data;
00869         create_landmark(self->mNameEditor->getText().c_str(), "", self->mPosGlobal);
00870 }
00871 */
00872 
00873 // static
00874 void LLPanelClassified::onClickSet(void* data)
00875 {
00876     LLPanelClassified* self = (LLPanelClassified*)data;
00877 
00878         // Save location for later.
00879         self->mPosGlobal = gAgent.getPositionGlobal();
00880 
00881         LLString location_text;
00882         location_text.assign("(will update after publish)");
00883         location_text.append(", ");
00884 
00885     S32 region_x = llround((F32)self->mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS;
00886     S32 region_y = llround((F32)self->mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS;
00887         S32 region_z = llround((F32)self->mPosGlobal.mdV[VZ]);
00888    
00889         location_text.append(self->mSimName);
00890     location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
00891 
00892         self->mLocationEditor->setText(location_text);
00893         self->mLocationChanged = true;
00894 
00895         // Set this to null so it updates on the next save.
00896         self->mParcelID.setNull();
00897 
00898         onCommitAny(NULL, data);
00899 }
00900 
00901 
00902 BOOL LLPanelClassified::checkDirty()
00903 {
00904         mDirty = FALSE;
00905         if      ( mSnapshotCtrl )                       mDirty |= mSnapshotCtrl->isDirty();
00906         if      ( mNameEditor )                         mDirty |= mNameEditor->isDirty();
00907         if      ( mDescEditor )                         mDirty |= mDescEditor->isDirty();
00908         if      ( mLocationEditor )                     mDirty |= mLocationEditor->isDirty();
00909         if  ( mLocationChanged )                mDirty |= TRUE;
00910         if      ( mCategoryCombo )                      mDirty |= mCategoryCombo->isDirty();
00911         if      ( mMatureCheck )                        mDirty |= mMatureCheck->isDirty();
00912         if      ( mAutoRenewCheck )                     mDirty |= mAutoRenewCheck->isDirty();
00913 
00914         return mDirty;
00915 }
00916 
00917 // static
00918 void LLPanelClassified::onCommitAny(LLUICtrl* ctrl, void* data)
00919 {
00920         LLPanelClassified* self = (LLPanelClassified*)data;
00921         if (self)
00922         {
00923                 self->checkDirty();
00924         }
00925 }
00926 
00927 // static
00928 void LLPanelClassified::onFocusReceived(LLUICtrl* ctrl, void* data)
00929 {
00930         // allow the data to be saved
00931         onCommitAny(ctrl, data);
00932 }
00933 
00934 
00935 void LLPanelClassified::sendClassifiedClickMessage(const char* type)
00936 {
00937         // You're allowed to click on your own ads to reassure yourself
00938         // that the system is working.
00939         std::vector<std::string> strings;
00940         strings.push_back(mClassifiedID.asString());
00941         strings.push_back(type);
00942         LLUUID no_invoice;
00943 
00944         // New classified click-through handling
00945         LLSD body;
00946         body["type"] = type;
00947         body["from_search"] = mFromSearch;
00948         body["classified_id"] = mClassifiedID;
00949         std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
00950 
00951         // If the capability exists send to the new database, otherwise send to the old one.
00952         if (!url.empty())
00953         {
00954                 llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl;
00955                 LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
00956         }
00957         else
00958         {
00959                 send_generic_message("classifiedclick", strings, no_invoice);
00960         }
00961 }
00962 
00964 
00965 LLFloaterPriceForListing::LLFloaterPriceForListing()
00966 :       LLFloater("PriceForListing"),
00967         mCallback(NULL),
00968         mUserData(NULL)
00969 { }
00970 
00971 //virtual
00972 LLFloaterPriceForListing::~LLFloaterPriceForListing()
00973 { }
00974 
00975 //virtual
00976 BOOL LLFloaterPriceForListing::postBuild()
00977 {
00978         LLLineEditor* edit = LLUICtrlFactory::getLineEditorByName(this, "price_edit");
00979         if (edit)
00980         {
00981                 edit->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32);
00982                 LLString min_price = llformat("%d", MINIMUM_PRICE_FOR_LISTING);
00983                 edit->setText(min_price);
00984                 edit->selectAll();
00985                 edit->setFocus(TRUE);
00986         }
00987 
00988         childSetAction("set_price_btn", onClickSetPrice, this);
00989 
00990         childSetAction("cancel_btn", onClickCancel, this);
00991 
00992         setDefaultBtn("set_price_btn");
00993         return TRUE;
00994 }
00995 
00996 //static
00997 void LLFloaterPriceForListing::show( void (*callback)(S32, LLString, void*), void* userdata)
00998 {
00999         LLFloaterPriceForListing *self = new LLFloaterPriceForListing();
01000 
01001         // Builds and adds to gFloaterView
01002         gUICtrlFactory->buildFloater(self, "floater_price_for_listing.xml");
01003         self->center();
01004 
01005         self->mCallback = callback;
01006         self->mUserData = userdata;
01007 }
01008 
01009 //static
01010 void LLFloaterPriceForListing::onClickSetPrice(void* data)
01011 {
01012         buttonCore(0, data);
01013 }
01014 
01015 //static
01016 void LLFloaterPriceForListing::onClickCancel(void* data)
01017 {
01018         buttonCore(1, data);
01019 }
01020 
01021 //static
01022 void LLFloaterPriceForListing::buttonCore(S32 button, void* data)
01023 {
01024         LLFloaterPriceForListing* self = (LLFloaterPriceForListing*)data;
01025 
01026         if (self->mCallback)
01027         {
01028                 LLString text = self->childGetText("price_edit");
01029                 self->mCallback(button, text, self->mUserData);
01030                 self->close();
01031         }
01032 }

Generated on Thu Jul 1 06:08:56 2010 for Second Life Viewer by  doxygen 1.4.7