00001
00032
00033
00034
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 "llcommandhandler.h"
00052 #include "llviewercontrol.h"
00053 #include "lllineeditor.h"
00054 #include "llfloateravatarinfo.h"
00055 #include "llfloaterclassified.h"
00056 #include "lltabcontainervertical.h"
00057 #include "lltextbox.h"
00058 #include "llcombobox.h"
00059 #include "llviewertexteditor.h"
00060 #include "lltexturectrl.h"
00061 #include "lluiconstants.h"
00062 #include "llurldispatcher.h"
00063 #include "lluictrlfactory.h"
00064 #include "llviewerparcelmgr.h"
00065 #include "llviewerwindow.h"
00066 #include "llworldmap.h"
00067 #include "llfloaterworldmap.h"
00068 #include "llviewergenericmessage.h"
00069 #include "llviewerregion.h"
00070 #include "llviewerwindow.h"
00071 #include "llappviewer.h"
00072
00073 const S32 MINIMUM_PRICE_FOR_LISTING = 50;
00074 const S32 MATURE_CONTENT = 1;
00075 const S32 NON_MATURE_CONTENT = 2;
00076 const S32 DECLINE_TO_STATE = 0;
00077
00078
00079 std::list<LLPanelClassified*> LLPanelClassified::sAllPanels;
00080
00081
00082
00083
00084
00085
00086 class LLDispatchClassifiedClickThrough : public LLDispatchHandler
00087 {
00088 public:
00089 virtual bool operator()(
00090 const LLDispatcher* dispatcher,
00091 const std::string& key,
00092 const LLUUID& invoice,
00093 const sparam_t& strings)
00094 {
00095 if (strings.size() != 4) return false;
00096 LLUUID classified_id(strings[0]);
00097 S32 teleport_clicks = atoi(strings[1].c_str());
00098 S32 map_clicks = atoi(strings[2].c_str());
00099 S32 profile_clicks = atoi(strings[3].c_str());
00100 LLPanelClassified::setClickThrough(classified_id, teleport_clicks,
00101 map_clicks,
00102 profile_clicks,
00103 false);
00104 return true;
00105 }
00106 };
00107 static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 LLPanelClassified::LLPanelClassified(bool in_finder, bool from_search)
00151 : LLPanel("Classified Panel"),
00152 mInFinder(in_finder),
00153 mFromSearch(from_search),
00154 mDirty(false),
00155 mForceClose(false),
00156 mLocationChanged(false),
00157 mClassifiedID(),
00158 mCreatorID(),
00159 mPriceForListing(0),
00160 mDataRequested(FALSE),
00161 mPaidFor(FALSE),
00162 mPosGlobal(),
00163 mSnapshotCtrl(NULL),
00164 mNameEditor(NULL),
00165 mDescEditor(NULL),
00166 mLocationEditor(NULL),
00167 mCategoryCombo(NULL),
00168 mMatureCombo(NULL),
00169 mAutoRenewCheck(NULL),
00170 mUpdateBtn(NULL),
00171 mTeleportBtn(NULL),
00172 mMapBtn(NULL),
00173 mProfileBtn(NULL),
00174 mInfoText(NULL),
00175 mSetBtn(NULL),
00176 mClickThroughText(NULL),
00177 mTeleportClicksOld(0),
00178 mMapClicksOld(0),
00179 mProfileClicksOld(0),
00180 mTeleportClicksNew(0),
00181 mMapClicksNew(0),
00182 mProfileClicksNew(0)
00183
00184 {
00185 sAllPanels.push_back(this);
00186
00187 std::string classified_def_file;
00188 if (mInFinder)
00189 {
00190 LLUICtrlFactory::getInstance()->buildPanel(this, "panel_classified.xml");
00191 }
00192 else
00193 {
00194 LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_classified.xml");
00195 }
00196
00197
00198 gGenericDispatcher.addHandler("classifiedclickthrough",
00199 &sClassifiedClickThrough);
00200 }
00201
00202
00203 LLPanelClassified::~LLPanelClassified()
00204 {
00205 sAllPanels.remove(this);
00206 }
00207
00208
00209 void LLPanelClassified::reset()
00210 {
00211 mClassifiedID.setNull();
00212 mCreatorID.setNull();
00213 mParcelID.setNull();
00214
00215
00216 mDataRequested = TRUE;
00217
00218 mDirty = false;
00219 mPaidFor = FALSE;
00220
00221 mPosGlobal.clearVec();
00222
00223 clearCtrls();
00224 }
00225
00226
00227 BOOL LLPanelClassified::postBuild()
00228 {
00229 mSnapshotCtrl = getChild<LLTextureCtrl>("snapshot_ctrl");
00230 mSnapshotCtrl->setCommitCallback(onCommitAny);
00231 mSnapshotCtrl->setCallbackUserData(this);
00232 mSnapshotSize = mSnapshotCtrl->getRect();
00233
00234 mNameEditor = getChild<LLLineEditor>("given_name_editor");
00235 mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN);
00236 mNameEditor->setCommitOnFocusLost(TRUE);
00237 mNameEditor->setFocusReceivedCallback(focusReceived, this);
00238 mNameEditor->setCommitCallback(onCommitAny);
00239 mNameEditor->setCallbackUserData(this);
00240 mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII );
00241
00242 mDescEditor = getChild<LLTextEditor>("desc_editor");
00243 mDescEditor->setCommitOnFocusLost(TRUE);
00244 mDescEditor->setFocusReceivedCallback(focusReceived, this);
00245 mDescEditor->setCommitCallback(onCommitAny);
00246 mDescEditor->setCallbackUserData(this);
00247 mDescEditor->setTabsToNextField(TRUE);
00248
00249 mLocationEditor = getChild<LLLineEditor>("location_editor");
00250
00251 mSetBtn = getChild<LLButton>( "set_location_btn");
00252 mSetBtn->setClickedCallback(onClickSet);
00253 mSetBtn->setCallbackUserData(this);
00254
00255 mTeleportBtn = getChild<LLButton>( "classified_teleport_btn");
00256 mTeleportBtn->setClickedCallback(onClickTeleport);
00257 mTeleportBtn->setCallbackUserData(this);
00258
00259 mMapBtn = getChild<LLButton>( "classified_map_btn");
00260 mMapBtn->setClickedCallback(onClickMap);
00261 mMapBtn->setCallbackUserData(this);
00262
00263 if(mInFinder)
00264 {
00265 mProfileBtn = getChild<LLButton>( "classified_profile_btn");
00266 mProfileBtn->setClickedCallback(onClickProfile);
00267 mProfileBtn->setCallbackUserData(this);
00268 }
00269
00270 mCategoryCombo = getChild<LLComboBox>( "classified_category_combo");
00271 LLClassifiedInfo::cat_map::iterator iter;
00272 for (iter = LLClassifiedInfo::sCategories.begin();
00273 iter != LLClassifiedInfo::sCategories.end();
00274 iter++)
00275 {
00276 mCategoryCombo->add(iter->second, (void *)((intptr_t)iter->first), ADD_BOTTOM);
00277 }
00278 mCategoryCombo->setCurrentByIndex(0);
00279 mCategoryCombo->setCommitCallback(onCommitAny);
00280 mCategoryCombo->setCallbackUserData(this);
00281
00282 mMatureCombo = getChild<LLComboBox>( "classified_mature_check");
00283 mMatureCombo->setCurrentByIndex(0);
00284 mMatureCombo->setCommitCallback(onCommitAny);
00285 mMatureCombo->setCallbackUserData(this);
00286 if (gAgent.isTeen())
00287 {
00288
00289 mMatureCombo->setVisible(FALSE);
00290 mMatureCombo->setCurrentByIndex(NON_MATURE_CONTENT);
00291 }
00292
00293 if (!mInFinder)
00294 {
00295 mAutoRenewCheck = getChild<LLCheckBoxCtrl>( "auto_renew_check");
00296 mAutoRenewCheck->setCommitCallback(onCommitAny);
00297 mAutoRenewCheck->setCallbackUserData(this);
00298 }
00299
00300 mUpdateBtn = getChild<LLButton>("classified_update_btn");
00301 mUpdateBtn->setClickedCallback(onClickUpdate);
00302 mUpdateBtn->setCallbackUserData(this);
00303
00304 if (!mInFinder)
00305 {
00306 mClickThroughText = getChild<LLTextBox>("click_through_text");
00307 }
00308
00309 return TRUE;
00310 }
00311
00312 BOOL LLPanelClassified::titleIsValid()
00313 {
00314
00315
00316 const LLString& name = mNameEditor->getText();
00317 if (name.empty())
00318 {
00319 gViewerWindow->alertXml("BlankClassifiedName");
00320 return FALSE;
00321 }
00322 if (!isalnum(name[0]))
00323 {
00324 gViewerWindow->alertXml("ClassifiedMustBeAlphanumeric");
00325 return FALSE;
00326 }
00327
00328 return TRUE;
00329 }
00330
00331 void LLPanelClassified::apply()
00332 {
00333
00334
00335 if (checkDirty() && mPaidFor)
00336 {
00337 sendClassifiedInfoUpdate();
00338 }
00339 }
00340
00341
00342
00343 void LLPanelClassified::saveCallback(S32 option, void* data)
00344 {
00345 LLPanelClassified* self = (LLPanelClassified*)data;
00346 switch(option)
00347 {
00348 case 0:
00349 self->sendClassifiedInfoUpdate();
00350
00351
00352 case 1:
00353 {
00354 self->mForceClose = true;
00355
00356 LLView* view = self;
00357 while (view)
00358 {
00359 LLFloater* floaterp = dynamic_cast<LLFloater*>(view);
00360 if (floaterp)
00361 {
00362 floaterp->close();
00363 break;
00364 }
00365 view = view->getParent();
00366 }
00367 }
00368 break;
00369
00370 case 2:
00371 default:
00372 LLAppViewer::instance()->abortQuit();
00373 break;
00374 }
00375 }
00376
00377 BOOL LLPanelClassified::canClose()
00378 {
00379 if (mForceClose || !checkDirty())
00380 return TRUE;
00381
00382 LLString::format_map_t args;
00383 args["[NAME]"] = mNameEditor->getText();
00384 LLAlertDialog::showXml("ClassifiedSave", args, saveCallback, this);
00385 return FALSE;
00386 }
00387
00388
00389 void LLPanelClassified::initNewClassified()
00390 {
00391
00392 mClassifiedID.generate();
00393
00394 mCreatorID = gAgent.getID();
00395
00396 mPosGlobal = gAgent.getPositionGlobal();
00397
00398 mPaidFor = FALSE;
00399
00400
00401 LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
00402 if (parcel)
00403 {
00404 mNameEditor->setText(parcel->getName());
00405
00406 mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID());
00407
00408 mCategoryCombo->setCurrentByIndex(0);
00409 }
00410
00411 mUpdateBtn->setLabel(getString("publish_txt"));
00412 }
00413
00414
00415 void LLPanelClassified::setClassifiedID(const LLUUID& id)
00416 {
00417 mClassifiedID = id;
00418 }
00419
00420
00421 void LLPanelClassified::setClickThrough(const LLUUID& classified_id,
00422 S32 teleport,
00423 S32 map,
00424 S32 profile,
00425 bool from_new_table)
00426 {
00427 for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
00428 {
00429 LLPanelClassified* self = *iter;
00430
00431 if (self->mClassifiedID != classified_id)
00432 {
00433 continue;
00434 }
00435
00436
00437
00438
00439
00440 if (from_new_table)
00441 {
00442 self->mTeleportClicksNew = teleport;
00443 self->mMapClicksNew = map;
00444 self->mProfileClicksNew = profile;
00445 }
00446 else
00447 {
00448 self->mTeleportClicksOld = teleport;
00449 self->mMapClicksOld = map;
00450 self->mProfileClicksOld = profile;
00451 }
00452
00453 if (self->mClickThroughText)
00454 {
00455 std::string msg = llformat("Clicks: %d teleport, %d map, %d profile",
00456 self->mTeleportClicksNew + self->mTeleportClicksOld,
00457 self->mMapClicksNew + self->mMapClicksOld,
00458 self->mProfileClicksNew + self->mProfileClicksOld);
00459 self->mClickThroughText->setText(msg);
00460 }
00461 }
00462 }
00463
00464
00465
00466 void LLPanelClassified::markForServerRequest()
00467 {
00468 mDataRequested = FALSE;
00469 }
00470
00471
00472 std::string LLPanelClassified::getClassifiedName()
00473 {
00474 return mNameEditor->getText();
00475 }
00476
00477
00478 void LLPanelClassified::sendClassifiedInfoRequest()
00479 {
00480 LLMessageSystem *msg = gMessageSystem;
00481
00482 if (mClassifiedID != mRequestedID)
00483 {
00484 msg->newMessageFast(_PREHASH_ClassifiedInfoRequest);
00485 msg->nextBlockFast(_PREHASH_AgentData);
00486 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
00487 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
00488 msg->nextBlockFast(_PREHASH_Data);
00489 msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID);
00490 gAgent.sendReliableMessage();
00491
00492 mDataRequested = TRUE;
00493 mRequestedID = mClassifiedID;
00494
00495
00496
00497 std::string url = gAgent.getRegion()->getCapability("SearchStatRequest");
00498 LLSD body;
00499 body["classified_id"] = mClassifiedID;
00500
00501 if (!url.empty())
00502 {
00503 llinfos << "Classified stat request via capability" << llendl;
00504 LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID));
00505 }
00506 }
00507 }
00508
00509
00510 void LLPanelClassified::sendClassifiedInfoUpdate()
00511 {
00512
00513
00514 if (mClassifiedID.isNull())
00515 {
00516
00517 mClassifiedID.generate();
00518 }
00519
00520 LLMessageSystem* msg = gMessageSystem;
00521
00522 msg->newMessageFast(_PREHASH_ClassifiedInfoUpdate);
00523 msg->nextBlockFast(_PREHASH_AgentData);
00524 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00525 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00526 msg->nextBlockFast(_PREHASH_Data);
00527 msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID);
00528
00529 U32 category = mCategoryCombo->getCurrentIndex() + 1;
00530 msg->addU32Fast(_PREHASH_Category, category);
00531 msg->addStringFast(_PREHASH_Name, mNameEditor->getText());
00532 msg->addStringFast(_PREHASH_Desc, mDescEditor->getText());
00533
00534
00535 msg->addUUIDFast(_PREHASH_ParcelID, mParcelID);
00536
00537 msg->addU32Fast(_PREHASH_ParentEstate, 0);
00538 msg->addUUIDFast(_PREHASH_SnapshotID, mSnapshotCtrl->getImageAssetID());
00539 msg->addVector3dFast(_PREHASH_PosGlobal, mPosGlobal);
00540 BOOL mature = mMatureCombo->getCurrentIndex() == MATURE_CONTENT;
00541 BOOL auto_renew = FALSE;
00542 if (mAutoRenewCheck)
00543 {
00544 auto_renew = mAutoRenewCheck->get();
00545 }
00546 U8 flags = pack_classified_flags(mature, auto_renew);
00547 msg->addU8Fast(_PREHASH_ClassifiedFlags, flags);
00548 msg->addS32("PriceForListing", mPriceForListing);
00549 gAgent.sendReliableMessage();
00550
00551 mDirty = false;
00552 }
00553
00554
00555
00556 void LLPanelClassified::processClassifiedInfoReply(LLMessageSystem *msg, void **)
00557 {
00558 lldebugs << "processClassifiedInfoReply()" << llendl;
00559
00560
00561 LLUUID agent_id;
00562 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
00563 if (agent_id != gAgent.getID())
00564 {
00565 llwarns << "Agent ID mismatch in processClassifiedInfoReply"
00566 << llendl;
00567 return;
00568 }
00569
00570 LLUUID classified_id;
00571 msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id);
00572
00573 LLUUID creator_id;
00574 msg->getUUIDFast(_PREHASH_Data, _PREHASH_CreatorID, creator_id);
00575
00576 LLUUID parcel_id;
00577 msg->getUUIDFast(_PREHASH_Data, _PREHASH_ParcelID, parcel_id);
00578
00579 char name[DB_PARCEL_NAME_SIZE];
00580 msg->getStringFast(_PREHASH_Data, _PREHASH_Name, DB_PARCEL_NAME_SIZE, name);
00581
00582 char desc[DB_PICK_DESC_SIZE];
00583 msg->getStringFast(_PREHASH_Data, _PREHASH_Desc, DB_PICK_DESC_SIZE, desc);
00584
00585 LLUUID snapshot_id;
00586 msg->getUUIDFast(_PREHASH_Data, _PREHASH_SnapshotID, snapshot_id);
00587
00588
00589
00590 char buffer[256];
00591 LLString location_text;
00592
00593 msg->getStringFast(_PREHASH_Data, _PREHASH_ParcelName, 256, buffer);
00594 if (buffer[0] != '\0')
00595 {
00596 location_text.assign(buffer);
00597 location_text.append(", ");
00598 }
00599 else
00600 {
00601 location_text.assign("");
00602 }
00603
00604 char sim_name[256];
00605 msg->getStringFast(_PREHASH_Data, _PREHASH_SimName, 256, sim_name);
00606
00607 LLVector3d pos_global;
00608 msg->getVector3dFast(_PREHASH_Data, _PREHASH_PosGlobal, pos_global);
00609
00610 S32 region_x = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
00611 S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
00612 S32 region_z = llround((F32)pos_global.mdV[VZ]);
00613
00614 snprintf(buffer, sizeof(buffer), "%s (%d, %d, %d)", sim_name, region_x, region_y, region_z);
00615 location_text.append(buffer);
00616
00617 U8 flags;
00618 msg->getU8Fast(_PREHASH_Data, _PREHASH_ClassifiedFlags, flags);
00619
00620 bool mature = is_cf_mature(flags);
00621 bool auto_renew = is_cf_auto_renew(flags);
00622
00623 U32 date = 0;
00624 msg->getU32Fast(_PREHASH_Data, _PREHASH_CreationDate, date);
00625 time_t tim = date;
00626 tm *now=localtime(&tim);
00627
00628
00629 U32 expiration_date = 0;
00630 msg->getU32("Data", "ExpirationDate", expiration_date);
00631
00632 U32 category = 0;
00633 msg->getU32Fast(_PREHASH_Data, _PREHASH_Category, category);
00634
00635 S32 price_for_listing = 0;
00636 msg->getS32("Data", "PriceForListing", price_for_listing);
00637
00638
00639 for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
00640 {
00641 LLPanelClassified* self = *iter;
00642
00643 if (self->mClassifiedID != classified_id)
00644 {
00645 continue;
00646 }
00647
00648
00649 self->mClassifiedID = classified_id;
00650 self->mCreatorID = creator_id;
00651 self->mParcelID = parcel_id;
00652 self->mPriceForListing = price_for_listing;
00653 self->mSimName.assign(sim_name);
00654 self->mPosGlobal = pos_global;
00655
00656
00657 self->mNameEditor->setText(LLString(name));
00658 self->mDescEditor->setText(LLString(desc));
00659 self->mSnapshotCtrl->setImageAssetID(snapshot_id);
00660 self->mLocationEditor->setText(location_text);
00661 self->mLocationChanged = false;
00662
00663 self->mCategoryCombo->setCurrentByIndex(category - 1);
00664 if(mature)
00665 {
00666 self->mMatureCombo->setCurrentByIndex(MATURE_CONTENT);
00667 }
00668 else
00669 {
00670 self->mMatureCombo->setCurrentByIndex(NON_MATURE_CONTENT);
00671 }
00672 if (self->mAutoRenewCheck)
00673 {
00674 self->mAutoRenewCheck->set(auto_renew);
00675 }
00676
00677 LLString datestr = llformat("%02d/%02d/%d", now->tm_mon+1, now->tm_mday, now->tm_year+1900);
00678 LLString::format_map_t string_args;
00679 string_args["[DATE]"] = datestr;
00680 string_args["[AMT]"] = llformat("%d", price_for_listing);
00681 self->childSetText("classified_info_text", self->getString("ad_placed_paid", string_args));
00682
00683
00684 self->mPaidFor = TRUE;
00685
00686 self->mUpdateBtn->setLabel(self->getString("update_txt"));
00687
00688 self->resetDirty();
00689
00690 self->resetDirty();
00691 }
00692 }
00693
00694 void LLPanelClassified::draw()
00695 {
00696 refresh();
00697
00698 LLPanel::draw();
00699 }
00700
00701
00702 void LLPanelClassified::refresh()
00703 {
00704 if (!mDataRequested)
00705 {
00706 sendClassifiedInfoRequest();
00707 }
00708
00709
00710 BOOL godlike = gAgent.isGodlike();
00711 BOOL is_self = (gAgent.getID() == mCreatorID);
00712
00713
00714 if (mInFinder)
00715 {
00716
00717
00718
00719 mSnapshotCtrl->setEnabled(godlike);
00720 if(godlike)
00721 {
00722
00723 mSnapshotCtrl->setOrigin(20, 175);
00724 mSnapshotCtrl->reshape(300, 200);
00725 }
00726 else
00727 {
00728 mSnapshotCtrl->setOrigin(mSnapshotSize.mLeft, mSnapshotSize.mBottom);
00729 mSnapshotCtrl->reshape(mSnapshotSize.getWidth(), mSnapshotSize.getHeight());
00730
00731 }
00732 mNameEditor->setEnabled(godlike);
00733 mDescEditor->setEnabled(godlike);
00734 mCategoryCombo->setEnabled(godlike);
00735 mCategoryCombo->setVisible(godlike);
00736
00737 mMatureCombo->setEnabled(godlike);
00738 mMatureCombo->setVisible(godlike);
00739
00740
00741
00742
00743 mSetBtn->setVisible(FALSE);
00744 mSetBtn->setEnabled(FALSE);
00745
00746 mUpdateBtn->setEnabled(godlike);
00747 mUpdateBtn->setVisible(godlike);
00748 }
00749 else
00750 {
00751 mSnapshotCtrl->setEnabled(is_self);
00752 mNameEditor->setEnabled(is_self);
00753 mDescEditor->setEnabled(is_self);
00754
00755 mCategoryCombo->setEnabled(is_self);
00756
00757 mMatureCombo->setEnabled(is_self);
00758
00759 if (mAutoRenewCheck)
00760 {
00761 mAutoRenewCheck->setEnabled(is_self);
00762 mAutoRenewCheck->setVisible(is_self);
00763 }
00764
00765 mClickThroughText->setEnabled(is_self);
00766 mClickThroughText->setVisible(is_self);
00767
00768 mSetBtn->setVisible(is_self);
00769 mSetBtn->setEnabled(is_self);
00770
00771 mUpdateBtn->setEnabled(is_self && checkDirty());
00772 mUpdateBtn->setVisible(is_self);
00773 }
00774 }
00775
00776
00777 void LLPanelClassified::onClickUpdate(void* data)
00778 {
00779 LLPanelClassified* self = (LLPanelClassified*)data;
00780
00781 if(self == NULL) return;
00782
00783
00784
00785 if ( ! self->titleIsValid() )
00786 {
00787 return;
00788 };
00789
00790
00791 if(self->mMatureCombo->getCurrentIndex() == DECLINE_TO_STATE)
00792 {
00793 LLString::format_map_t args;
00794 gViewerWindow->alertXml("SetClassifiedMature", &callbackConfirmMature, self);
00795 return;
00796 }
00797
00798
00799 self->gotMature();
00800 }
00801
00802
00803 void LLPanelClassified::callbackConfirmMature(S32 option, void* data)
00804 {
00805 LLPanelClassified* self = (LLPanelClassified*)data;
00806 self->confirmMature(option);
00807 }
00808
00809
00810 void LLPanelClassified::confirmMature(S32 option)
00811 {
00812
00813
00814
00815 switch(option)
00816 {
00817 case 0:
00818 mMatureCombo->setCurrentByIndex(MATURE_CONTENT);
00819 break;
00820 case 1:
00821 mMatureCombo->setCurrentByIndex(NON_MATURE_CONTENT);
00822 break;
00823 default:
00824 return;
00825 }
00826
00827
00828 gotMature();
00829 }
00830
00831
00832
00833 void LLPanelClassified::gotMature()
00834 {
00835
00836 if (mPaidFor)
00837 {
00838 callbackConfirmPublish(0, this);
00839 }
00840 else
00841 {
00842
00843 LLFloaterPriceForListing::show( callbackGotPriceForListing, this );
00844 }
00845 }
00846
00847
00848 void LLPanelClassified::callbackGotPriceForListing(S32 option, LLString text, void* data)
00849 {
00850 LLPanelClassified* self = (LLPanelClassified*)data;
00851
00852
00853 if (option != 0) return;
00854
00855 S32 price_for_listing = strtol(text.c_str(), NULL, 10);
00856 if (price_for_listing < MINIMUM_PRICE_FOR_LISTING)
00857 {
00858 LLString::format_map_t args;
00859 LLString price_text = llformat("%d", MINIMUM_PRICE_FOR_LISTING);
00860 args["[MIN_PRICE]"] = price_text;
00861
00862 gViewerWindow->alertXml("MinClassifiedPrice", args);
00863 return;
00864 }
00865
00866
00867
00868 self->mPriceForListing = price_for_listing;
00869
00870 LLString::format_map_t args;
00871 args["[AMOUNT]"] = llformat("%d", price_for_listing);
00872 gViewerWindow->alertXml("PublishClassified", args, &callbackConfirmPublish, self);
00873
00874 }
00875
00876 void LLPanelClassified::resetDirty()
00877 {
00878
00879 if (mSnapshotCtrl)
00880 mSnapshotCtrl->resetDirty();
00881 if (mNameEditor)
00882 mNameEditor->resetDirty();
00883 if (mDescEditor)
00884 mDescEditor->resetDirty();
00885 if (mLocationEditor)
00886 mLocationEditor->resetDirty();
00887 mLocationChanged = false;
00888 if (mCategoryCombo)
00889 mCategoryCombo->resetDirty();
00890 if (mMatureCombo)
00891 mMatureCombo->resetDirty();
00892 if (mAutoRenewCheck)
00893 mAutoRenewCheck->resetDirty();
00894 }
00895
00896
00897 void LLPanelClassified::confirmPublish(S32 option)
00898 {
00899
00900 if (option != 0) return;
00901
00902 sendClassifiedInfoUpdate();
00903
00904
00905
00906 if (mInFinder)
00907 {
00908
00909
00910
00911 }
00912 else
00913 {
00914 LLTabContainer* tab = (LLTabContainer*)getParent();
00915 tab->setCurrentTabName(mNameEditor->getText());
00916 }
00917
00918 resetDirty();
00919 }
00920
00921
00922 void LLPanelClassified::callbackConfirmPublish(S32 option, void* data)
00923 {
00924 LLPanelClassified* self = (LLPanelClassified*)data;
00925 self->confirmPublish(option);
00926 }
00927
00928
00929 void LLPanelClassified::onClickTeleport(void* data)
00930 {
00931 LLPanelClassified* self = (LLPanelClassified*)data;
00932
00933 if (!self->mPosGlobal.isExactlyZero())
00934 {
00935 gAgent.teleportViaLocation(self->mPosGlobal);
00936 gFloaterWorldMap->trackLocation(self->mPosGlobal);
00937
00938 self->sendClassifiedClickMessage("teleport");
00939 }
00940 }
00941
00942
00943
00944 void LLPanelClassified::onClickMap(void* data)
00945 {
00946 LLPanelClassified* self = (LLPanelClassified*)data;
00947 gFloaterWorldMap->trackLocation(self->mPosGlobal);
00948 LLFloaterWorldMap::show(NULL, TRUE);
00949
00950 self->sendClassifiedClickMessage("map");
00951 }
00952
00953
00954 void LLPanelClassified::onClickProfile(void* data)
00955 {
00956 LLPanelClassified* self = (LLPanelClassified*)data;
00957 LLFloaterAvatarInfo::showFromDirectory(self->mCreatorID);
00958 self->sendClassifiedClickMessage("profile");
00959 }
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971 void LLPanelClassified::onClickSet(void* data)
00972 {
00973 LLPanelClassified* self = (LLPanelClassified*)data;
00974
00975
00976 self->mPosGlobal = gAgent.getPositionGlobal();
00977
00978 LLString location_text;
00979 location_text.assign("(will update after publish)");
00980 location_text.append(", ");
00981
00982 S32 region_x = llround((F32)self->mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS;
00983 S32 region_y = llround((F32)self->mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS;
00984 S32 region_z = llround((F32)self->mPosGlobal.mdV[VZ]);
00985
00986 location_text.append(self->mSimName);
00987 location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
00988
00989 self->mLocationEditor->setText(location_text);
00990 self->mLocationChanged = true;
00991
00992
00993 self->mParcelID.setNull();
00994
00995 onCommitAny(NULL, data);
00996 }
00997
00998
00999 BOOL LLPanelClassified::checkDirty()
01000 {
01001 mDirty = FALSE;
01002 if ( mSnapshotCtrl ) mDirty |= mSnapshotCtrl->isDirty();
01003 if ( mNameEditor ) mDirty |= mNameEditor->isDirty();
01004 if ( mDescEditor ) mDirty |= mDescEditor->isDirty();
01005 if ( mLocationEditor ) mDirty |= mLocationEditor->isDirty();
01006 if ( mLocationChanged ) mDirty |= TRUE;
01007 if ( mCategoryCombo ) mDirty |= mCategoryCombo->isDirty();
01008 if ( mMatureCombo ) mDirty |= mMatureCombo->isDirty();
01009 if ( mAutoRenewCheck ) mDirty |= mAutoRenewCheck->isDirty();
01010
01011 return mDirty;
01012 }
01013
01014
01015 void LLPanelClassified::onCommitAny(LLUICtrl* ctrl, void* data)
01016 {
01017 LLPanelClassified* self = (LLPanelClassified*)data;
01018 if (self)
01019 {
01020 self->checkDirty();
01021 }
01022 }
01023
01024
01025 void LLPanelClassified::focusReceived(LLFocusableElement* ctrl, void* data)
01026 {
01027
01028 onCommitAny((LLUICtrl*)ctrl, data);
01029 }
01030
01031
01032 void LLPanelClassified::sendClassifiedClickMessage(const char* type)
01033 {
01034
01035
01036 LLSD body;
01037 body["type"] = type;
01038 body["from_search"] = mFromSearch;
01039 body["classified_id"] = mClassifiedID;
01040 body["parcel_id"] = mParcelID;
01041 body["dest_pos_global"] = mPosGlobal.getValue();
01042 body["region_name"] = mSimName;
01043
01044 std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
01045 llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl;
01046 LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
01047 }
01048
01050
01051 LLFloaterPriceForListing::LLFloaterPriceForListing()
01052 : LLFloater("PriceForListing"),
01053 mCallback(NULL),
01054 mUserData(NULL)
01055 { }
01056
01057
01058 LLFloaterPriceForListing::~LLFloaterPriceForListing()
01059 { }
01060
01061
01062 BOOL LLFloaterPriceForListing::postBuild()
01063 {
01064 LLLineEditor* edit = getChild<LLLineEditor>("price_edit");
01065 if (edit)
01066 {
01067 edit->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32);
01068 LLString min_price = llformat("%d", MINIMUM_PRICE_FOR_LISTING);
01069 edit->setText(min_price);
01070 edit->selectAll();
01071 edit->setFocus(TRUE);
01072 }
01073
01074 childSetAction("set_price_btn", onClickSetPrice, this);
01075
01076 childSetAction("cancel_btn", onClickCancel, this);
01077
01078 setDefaultBtn("set_price_btn");
01079 return TRUE;
01080 }
01081
01082
01083 void LLFloaterPriceForListing::show( void (*callback)(S32, LLString, void*), void* userdata)
01084 {
01085 LLFloaterPriceForListing *self = new LLFloaterPriceForListing();
01086
01087
01088 LLUICtrlFactory::getInstance()->buildFloater(self, "floater_price_for_listing.xml");
01089 self->center();
01090
01091 self->mCallback = callback;
01092 self->mUserData = userdata;
01093 }
01094
01095
01096 void LLFloaterPriceForListing::onClickSetPrice(void* data)
01097 {
01098 buttonCore(0, data);
01099 }
01100
01101
01102 void LLFloaterPriceForListing::onClickCancel(void* data)
01103 {
01104 buttonCore(1, data);
01105 }
01106
01107
01108 void LLFloaterPriceForListing::buttonCore(S32 button, void* data)
01109 {
01110 LLFloaterPriceForListing* self = (LLFloaterPriceForListing*)data;
01111
01112 if (self->mCallback)
01113 {
01114 LLString text = self->childGetText("price_edit");
01115 self->mCallback(button, text, self->mUserData);
01116 self->close();
01117 }
01118 }