C++ Builder IdPOP3 ListView

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

C++ Builder IdPOP3 ListView

Postby Smoke1 » Tue Jan 24, 2012 9:34 am

:!:
Last edited by Smoke1 on Sat Feb 11, 2012 4:16 pm, edited 2 times in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Tue Jan 24, 2012 4:44 pm

Smoke1 wrote:The below code works with the attachment, LISTCLICK but at the end I get MESSAGE: List Index out of bounds(4).


TIdPOP3::Retrieve() expects a message number that is relative to the POP3 server. You are passing it a ListView item index instead. Where and how do you populate your ListView? From the looks of the code you showed, I am assuming you have an OnConnect event handler assigned that populates the ListView based on the return value of the TIdPOP3::CheckMessages() method, is that right?

Smoke1 wrote:
Code: Select all
list->Selected->SubItems->Strings[0];


That line is not doing anything meaningful, but it will crash if no ListView item is actually selected. You need to check if the TListView::Selected property returns a NULL pointer before accessing the item, eg:

Code: Select all
TListItem *selected = list->Selected;
if (selected != NULL)
{
    ...
}


Smoke1 wrote:
Code: Select all
for( idx = 1; idx <=(mess->MessageParts->Count); idx ++)


This is wrong. The MessageParts collection is 0-indexed, but you are treating it as if it were 1-indexed instead. Once your loop moves past the last item in the collection, the last iteration of the loop will cause a bounds error when accessing the Items[] property. You need to fix your loop, eg:

Code: Select all
for( idx = 0; idx < mess->MessageParts->Count; ++idx )
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Tue Jan 24, 2012 8:01 pm

Life is Good, Until your Dead
Last edited by Smoke1 on Thu Jan 26, 2012 11:59 am, edited 1 time in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Wed Jan 25, 2012 3:04 am

Smoke1 wrote:Thank you for helping me below is the full start and the OnClick listClick code


There are some fundamental assumptions being made in your code that are wrong. An important one to watch out for is you are disconnecting and reconnecting between operations, expecting your indexes to stay consistent. As soon as you disconnect, the mailbox is unlocked and can be modified outside of your app (new emaild arriving, other clients downloading and deleting messages, etc), so your indexes may be invalid when you reconnect. POP3 is not designed for the type of management you are attempting. It is designed to do everything within a single session only. Connect, download, delete, disconnect. You are not doing it that way. Anytime you reconnect, you have to revalidate what is on the server before you then manipulate it. Otherwise, consider switching to IMAP instead, which is designed for managing messages.

Another bug in your code is you are still not looping through the TIdMessage::MessageParts collection correctly. You still have a bounds error. You changed the loop to start at index 0 now, but you are still looping to "<= Count" when you need to loop to "< Count" instead. The last item in the collection is at index "Count-1".

With that said, try something more like this:

Code: Select all
//TListView OnDeletion event handler
void __fastcall TForm5::listDeletion(TObject *Sender, TListItem *Item)
{
    delete (TIdMessage*) Item->Data;
}

void __fastcall TForm5::Button1Click(TObject *Sender)
{
    //Setup connection
    pop->Host = "pop.123.123.com";//
    pop->Username= "me@some.net"; // 
    pop->Password= "123";//   

    //connect to the server

    try
    {
        pop->Connect();                        
        //StatusBar1->Panels->Items[0]->Text = "Connected;
    }
    catch (const Exception &)
    {
        ShowMessage("Could not connect to pop server, please check your connection details");
        return;
    }

    try
    {
        //retrieve msgs
        fmailboxsize = pop->RetrieveMailBoxSize()/1024;

        msgcount = pop->CheckMessages();
        StatusBar1->Panels->Items[0]->Text = "Total Messages " + IntToStr(msgcount);

        //listview
        list->Items->Clear();
        for (int intindex = 1; intindex <= msgcount; ++intindex)
        {
            StatusBar1->Panels->Items[2]->Text = Format("Downloading Messages, %d of %d",
ARRAYOFCONST((intindex, msgcount)) );

            Update();

            TIdMessage *mess = new TIdMessage(NULL);
            try
            {
                pop->RetrieveHeader(intindex, mess);

                li = list->Items->Add();
                li->ImageIndex = 4;
                li->Caption =  mess->From->Text;
                li->SubItems->Add(mess->Subject);
                li->SubItems->Add(FormatDateTime("dd/mm/yyy h:nn:ss ampm", mess->Date));
                li->SubItems->Add(IntToStr(pop->RetrieveMsgSize(intindex)) + " b");
                li->Data = mess;
            }
            catch (const Exception &)
            {
                delete mess;
                throw;
            }
        }
    }
    __finally
    {
        pop->Disconnect();
    }
}

void __fastcall TForm5::listClick(TObject *Sender)
{
    //clear all components
    lvAttachments->Items->Clear();
    memo1->Clear();

    //check if any message is selected
    TListItem *selected = list->Selected;
    if (selected == NULL)
        return;

    TIdMessage *mess = (TIdMessage*) selected->Data;
    if (mess->Tag == 0)
    {
        //retrieve it's body
        pop->Connect();
        try
        {
            TIdMessage *tmp = new TIdMessage(NULL);
            try
            {
                //make sure it is the same message
                pop->RetrieveHeader(selected->Index + 1, tmp);
                if (tmp->MessageId != mess->MessageId)
                {
                    ShowMessage("Mailbox is out of date, please refresh.");
                    return;
                }

                tmp->Clear();
                pop->Retrieve(selected->Index + 1, tmp);
                tmp->Tag = 1;

                selected->Data = tmp;
                tmp = mess;
            }
            __finally
            {
               delete tmp;
            }
        }
        __finally
        {
            pop->Disconnect();
        }

        mess = (TIdMessage*) selected->Data;
    }

    Label2->Caption= mess->From->Text;
    Label1->Caption= mess->Recipients->EMailAddresses; 
    Label3->Caption= mess->Subject;
    Label4->Caption= FormatDateTime("mmm dd yyyy h:nn:ss ampm", mess->Date);

    //add msg body to memo
    memo1->Lines->Assign(mess->Body);

    for (int idx = 0; idx < mess->MessageParts->Count; ++idx)
    {
        TIdAttachment *Attachment = dynamic_cast<TIdAttachment*>(mess->MessageParts->Items[idx]);
        if (!Attachment)
            continue;

        li = lvAttachments->Items->Add();
        li->ImageIndex = 0;
        li->Caption = Attachment->FileName;
        li->SubItems->Add(Attachment->ContentType);

        StatusBar1->Panels->Items[1]->Text = Attachment->FileName;
    }
}

void __fastcall TForm5::Button2Click(TObject *Sender)
{
    TListItem *selected = list->Selected;
    if (selected == NULL)
    {
        //if the user pressed the button without selecting a message, inform them
        ShowMessage("Please select messages to delete");
        return;
    }

    //confirm if the user wants to delete the message
    if (MessageDlgPos("Are you sure you want to Delete the selected message?", mtConfirmation, mbYesNoCancel, 0, 200, 200, mbYes) != mbYes)
        return;

    TIdMessage *mess = (TIdMessage*) selected->Data;

    pop->Connect();
    try
    {
        //make sure it is the same message
        TIdMessage *tmp = new TIdMessage(NULL);
        try
        {
            pop->RetrieveHeader(selected->Index + 1, tmp);
            if (tmp->MessageId != mess->MessageId)
            {
                ShowMessage("Mailbox is out of date, please refresh.");
                return;
            }
        }
        __finally
        {
            delete tmp;
        }

        pop->Delete(selected->Index + 1);
    }
    __finally
    {
        pop->Disconnect();
    }

    selected->Delete();
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Thu Jan 26, 2012 11:08 am

Thank you Very much for your help, Ive been like a kid in a candy store with that code. Ive learn a great deal with your help with that code and I feel I have a better understanding of the code than before.
I have a few question, if you have the time.

The newly code you design for me works excellently, thank you for your time in this matter.

When program runs, I noticed, after clicking Button1, email Downloads . During this down load
Screen is lock, cant minumize screen or stop it(No Other Button will focus on click).
Now after the download is complete, Screen is controlable again all other buttons will work.

Other issue I dont know how to correct is, when I recieve emails with <html> no way to read this
in memo ContentType is TMessage1 is plain/text. Also nothing in memo1 but "This is a multi-part message in MIME format". when click on the email and subject starts out with =?ISO-8859-1?Q etc..
These email do not have attachments. I had switch to a different ISP and had a email I sent for testing with an attachment and message in the body standard type a email with message and attachment. On click it downloaded the email and showed me the attachment in ListView2 but did not deliver the Body message?.

Maybe this will have to wait another time but I was curious, On Listview1 is there away to add Image icon to show file attachment, or maybe show the attachment in the ListView1 like where it shows the Email its downloading. because without those You really dont know if there is an attachment til its downloading from the onclick event.

ListView has always been a tough one for me to work with.<sigh> as you could tell with my code you corrected for me. Oh yeah Thank you again, for all you did for me.

I have Followed you a long time, actually Your the reason I got as far as I did with this pop3. I mean this as a compliment lol.

Smoke1
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Thu Jan 26, 2012 2:58 pm

Smoke1 wrote:When program runs, I noticed, after clicking Button1, email Downloads . During this down load Screen is lock, cant minumize screen or stop it(No Other Button will focus on click). Now after the download is complete, Screen is controlable again all other buttons will work.


That is because you are doing everything in the context of the main thread. While your code is busy processing the emails, the main message loop is blocked and cannot process new messages until your code is finished. You can either drop a TIdAntiFreeze component onto your MainForm, or else move your processing into a separate worker thread.

Smoke1 wrote:when I recieve emails with <html> no way to read this in memo ContentType is TMessage1 is plain/text.


Then the emails are malformed, because that is not the correct ContentType for HTML emails. It needs to be either "text/html", "multipart/mixed", or "multipart/alternative", depending on the structure of the email. Have a look at this article: HTML Messages. It is geared more towards creating HTML emails rather than parsing them, but there is some structure information that you will find useful.

Smoke1 wrote:Also nothing in memo1 but "This is a multi-part message in MIME format".


That is normal. MIME encoded emails do not use the TIdMessage::Body property. They use the TIdMessage::MessageParts collection instead. Text and HTML pieces are stored as individual TIdText objects in the collection. The TIdMessage.::Body property holds the MIME preamble instead.

Smoke1 wrote:when click on the email and subject starts out with =?ISO-8859-1?Q etc..


Email headers cannot only hold ASCII characters, so MIME defines a special set of encoding rules for non-ASCII data. TIdMessage should be decoding that data automatically, though, unless you have set the TIdMessage::NoDecode property to true. If that property is false and the Subject property is not returning a decoded string, then the header is likely malformed in the email in a way that prevents TIdMessage from decoding it, so it just returns the original encoded data instead so you can decode it manually.

Smoke1 wrote:These email do not have attachments. I had switch to a different ISP and had a email I sent for testing with an attachment and message in the body standard type a email with message and attachment. On click it downloaded the email and showed me the attachment in ListView2 but did not deliver the Body message?


Because you are looking for the body text in the TIdMessage::Body property only, where it is not being stored in that situation. It is being stored in a TIdText object within the TIdMessage::MessageParts collection instead.

Smoke1 wrote:Maybe this will have to wait another time but I was curious, On Listview1 is there away to add Image icon to show file attachment, or maybe show the attachment in the ListView1 like where it shows the Email its downloading. because without those You really dont know if there is an attachment til its downloading from the onclick event.


In POP3, there is no way to detect the presence of attachments from the top-level email headers by themselves. You need to download and parse the entire content of the email to determine that. This is another reason why POP3 is not a suitable protocol for the type of management you want to accomplish. IMAP is more suited for this purpose. You can query IMAP for an email's structure without downloading the entire email. On the other hand, IMAP is a complex protocol to work with in general. So it is a trade-off one way or the other.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Sat Jan 28, 2012 9:29 am

.
Last edited by Smoke1 on Sat Feb 11, 2012 4:09 pm, edited 1 time in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Mon Jan 30, 2012 8:40 pm

Smoke1 wrote:I tried using methods you mention but no change in TMessage.
I tried TIdText, and I'm 100% sure I wrote it wrong as well.. lol


Try this instead:

Code: Select all
memo1->Clear();

if (IsHeaderMediaType(mess->ContentType, "multipart"))
{
   // MIME is designed to be processed in reverse order
   // from most complex to least complex

   for(int i = mess->MessageParts->Count-1; i >= 0; --i)
   {
      TIdMessagePart *Part = mess->MessageParts->Items[i];

      // only interested in top-level parts here...
      if (Part->ParentPart != -1)
         continue;

      if (IsHeaderMediaType(Part->ContentType, "multipart"))
      {
         bool FoundText = false;

         for (int j = mess->MessageParts->Count-1; j > Part->Index; --j)
         {
            TIdMessagePart *Part2 = mess->MessageParts->Items[j];

            // only interested in direct nested parts here...
            if (Part2->ParentPart != Part->Index)
               continue;

            ... other content types you want to support (HTML, RTF, etc) ...

            if (IsHeaderMediaType(Part2->ContentType, "text/plain"))
            {
               FoundText = true;

               TIdText *Text = dynamic_cast<TIdText*>(Part2);

               if (Text)
                  memo1->Lines->Assign(Text->Body);

               break;
            }
         }

         if (FoundText)
            break;

         continue;
      }

      ... other content types you want to support (HTML, RTF, etc) ...

      if (IsHeaderMediaType(Part->ContentType, "text/plain"))
      {
         TIdText *Text = dynamic_cast<TIdText*>(Part);

         if (Text)
            memo1->Lines->Assign(Text->Body);

         break;
      }
   }
}
else
{
   ... other content types you want to support (HTML, RTF, etc) ...

   if (IsHeaderMediaType(mess->ContentType, "text/plain")
      memo1->Lines->Assign(mess->Body);
}


Welcome to the wide world of MIME encoding!

Smoke1 wrote:On another Note. After I recieve my mail and especially when recieving
Attachment. How can I click on listview2 where my attachment is, and open
it up to read it. Say "jpeg/bmp", "doc","pdf", file. I thought it would be easy but Wow its not . LOL


If you want to load it in the user's default viewer app, then save the attachment to file using the TIdAttachment::SaveToFile() method, and then call the Win32 API ShellExecute() function with the full path and filename, and a NULL verb so the default registered verb for the file extension is invoked, eg:

Code: Select all
TIdAttachment *Attach = ....
String Filename = ...;
Attach->SaveToFile(Filename);
::ShellExecute(Handle, NULL, Filename.c_str(), 0, 0, SW_SHOWNORMAL);


Is that what you are asking?

Smoke1 wrote:I have a small section of code I use in other application and was wondering if there is a better way to write this section. This code works great and serves my purpose, It involves Listview1.
Is There a Better way to write This code for the iteration?


From the looks of the code, the text file consists of 3 lines per address book item, is that correct? If so, then try this code:

Code: Select all
#include <memory>

{
   ...

   lvAddressbk->Items->Clear();

   std::auto_ptr<TStringList> List(new TStringList);

   List->LoadFromFile("C:\\WorkAddressbk.txt");
   if ((List->Count % 3) != 0)
      throw Exception("Incorrect number of lines in the file");

   for(int b = 0; b < List->Count; b += 3)
   {
      TListItem *item = lvAddressbk->Items->Add();
      item->Caption = List->Strings[b];
      item->SubItems->Add(List->Strings[b+1]) ;
      item->SubItems->Add(List->Strings[b+2]) ;
   }

   ...
}


Smoke1 wrote:Like I said no problem with this code, just like to make it look more professional.


Personally, I would use the ListView in virtual mode instead (set the OwnerData property to true and assign an OnData event handler), eg:

Code: Select all
class TMyForm : public TForm
{
private:
   ...
   TStringList *slAddressbk;
   ...
};

__fastcall TMyForm::TMyForm(TComponent *Owner)
   : TForm(Owner)
{
   ...
   slAddressbk = new TStringList;
}

__fastcall TMyForm::~TMyForm()
{
   ...
   delete slAddressbk;
}

void __fastcall TMyForm::LoadAddressBook()
{
   lvAddressbk->Items->Count = 0;
   slAddressbk->Clear();

   slAddressbk->LoadFromFile("C:\\WorkAddressbk.txt");
   if ((slAddressbk->Count % 3) != 0)
   {
      slAddressbk->Clear();
      throw Exception("Incorrect number of lines in the file");
   }

   lvAddressbk->Items->Count = (slAddressbk->Count / 3);
}

void __fastcall TForm1::lvAddressbkData(TObject *Sender, TListItem *Item)
{
   int b = (Item->Index * 3);
   item->Caption = slAddressbk->Strings[b];
   item->SubItems->Add(slAddressbk->Strings[b+1]) ;
   item->SubItems->Add(slAddressbk->Strings[b+2]) ;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Tue Jan 31, 2012 5:31 pm

This Nation UNDER God, We Trust
Last edited by Smoke1 on Fri Feb 03, 2012 7:06 pm, edited 1 time in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Wed Feb 01, 2012 8:53 pm

Smoke1 wrote:there are a few I get from this site that only shows <html> characters. if I set

//... other content types you want to support (HTML, RTF, etc) ...
if (IsHeaderMediaType(mess->ContentType, "text/html"))
memo1->Lines->Assign(mess->Body);

here I get the <html> etc...


As you should be. That is how HTML works.

Smoke1 wrote:if I leave it as you had it...

//... other content types you want to support (HTML, RTF, etc) ...
if (IsHeaderMediaType(mess->ContentType, "text/plain"))
memo1->Lines->Assign(mess->Body);

Nothing shows in memo1.


Because there is no "text/plain" part in that email. MIME-encoded emails commonly, but are not required to, provide multiple representations of body content. It is customary to send a plain-text representation for email clients that do not support HTML, but not everyone does that.

Smoke1 wrote:all else works great in Standard email and if there is attachment, I get text in memo1 now..

I'm assuming theres nothing I can do about that, getting text without the <html> jargan. :lol:


You should not pull out the "text/html" data unless you are prepared to parse/display it as HTML. MIME is designed to allow multiple representations to be present so processors can use the representation that best suits them.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Thu Feb 02, 2012 3:22 pm

 .  
Last edited by Smoke1 on Sat Feb 11, 2012 4:12 pm, edited 1 time in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Mon Feb 06, 2012 3:01 pm

Smoke1 wrote:I used the listview virtual mode and in itself works fast and great, I tried to and set the list to be sorted but it wont do it. if I change the virtual mode to false and use your first method it works great sorts the lists how come.


In virtual mode, you do not sort the ListView itself, you sort your data instead and then invalidate the ListView so it can draw the updated data. In this case, I would not use a TStringList anymore to hold the ListView data, if for no other reason than it will complicate the sorting algorithm.

Try this instead:

Code: Select all
struct sAddressbkData
{
   // give these more meaningful names!
   String Caption;
   String SubItem1;
   String SubItem2;
};

class TForm1 : public TForm
{
...
private:
   TList *lAddressbk;
   void __fastcall ClearAddressbk();
...
};



Code: Select all
#include "listview.h"
#include <memory>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   lAddressbk = new TList;
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
   ClearAddressbk();
   delete lAddressbk;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ClearAddressbk()
{
   for (int i = 0; i < lAddressbk->Count; ++i)
      delete (sAddressbkData*) lAddressbk->Items[i];
   lAddressbk->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   lvAddressbk->Items->Count = 0;
   ClearAddressbk();

   std::auto_ptr<TStringList> slAddressbk(new TStringList);
   slAddressbk->LoadFromFile("C:\\WorkAddressbk.txt");
   if ((slAddressbk->Count % 3) != 0)
      throw Exception("Incorrect number of lines in the file");
   }

   lAddressbk->Capacity = (slAddressbk->Count / 3);
   for (int i = 0; i < lAddressbk->Capacity; ++i)
   {
      std::auto_ptr<sAddressbkData> data(new sAddressbkData);

      int idx = (i * 3);
      data->Caption  = slAddressbk->Strings[idx];
      data->SubItem1 = slAddressbk->Strings[idx+1];
      data->SubItem2 = slAddressbk->Strings[idx+2];

      lAddressbk->Add(data.get());
      data.release();
   }

   lvAddressbk->Items->Count = lAddressbk->Count;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkData(TObject *Sender, TListItem *Item)
{
   sAddressbkData *data = (sAddressbkData*) lAddressbk->Items[Item->Index];

   Item->Caption = data->Caption;
   Item->SubItems->Add(data->SubItem1);
   Item->SubItems->Add(data->SubItem2);
}
//---------------------------------------------------------------------------
int ColumnToSort = 0;
int __fastcall sAddressbkDataSortProc(void *Item1, void *Item2)
{
   sAddressbkData *data1 = (sAddressbkData*) Item1;
   sAddressbkData *data2 = (sAddressbkData*) Item2;

   switch (ColumnToSort)
   {
      case 0:
      default:
         return CompareText(data1->Caption, data2->Caption);
      case 1:
         return CompareText(data1->SubItem1, data2->SubItem1);
      case 2:
         return CompareText(data1->SubItem2, data2->SubItem2);
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkChange(TObject *Sender, TListItem *Item, TItemChange Change)
{
   lAddressbk->Sort(&sAddressbkDataSortProc);
   lvAddressbk->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkCustomDraw(TCustomListView *Sender, const TRect &ARect, bool &DefaultDraw)
{
   lvAddressbk->Canvas->Font->Color = clBlue;     
}
//---------------------------------------------------------------------------


Alternatively, using a std::vector to manage the ListView data memory management for you:

Code: Select all
#include <vector>

struct sAddressbkData
{
   // give these more meaningful names!
   String Caption;
   String SubItem1;
   String SubItem2;
};

class TForm1 : public TForm
{
...
private:
   std::vector<sAddressbkData> vecAddressbk;
...
};



Code: Select all
#include "listview.h"
#include <memory>
#include <algorithm>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   lvAddressbk->Items->Count = 0;
   vecAddressbk.clear();

   std::auto_ptr<TStringList> slAddressbk(new TStringList);
   slAddressbk->LoadFromFile("C:\\WorkAddressbk.txt");
   if ((slAddressbk->Count % 3) != 0)
      throw Exception("Incorrect number of lines in the file");
   }

   vecAddressbk.resize(slAddressbk->Count / 3);
   for (std::vector<sAddressbkData>::size_type i = 0; i < vecAddressbk.size(); ++i)
   {
      sAddressbkData &data = vecAddressbk[i];

      int idx = (i * 3);
      data.Caption  = slAddressbk->Strings[idx];
      data.SubItem1 = slAddressbk->Strings[idx+1];
      data.SubItem2 = slAddressbk->Strings[idx+2];
   }

   lvAddressbk->Items->Count = vecAddressbk.size();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkData(TObject *Sender, TListItem *Item)
{
   sAddressbkData &data = vecAddressbk[Item->Index];

   Item->Caption = data.Caption;
   Item->SubItems->Add(data.SubItem1);
   Item->SubItems->Add(data.SubItem2);
}
//---------------------------------------------------------------------------
int ColumnToSort = 0;
struct sAddressbkDataSortComparer
{
   bool operator ()(const sAddressbkData &lhs, const sAddressbkData &rhs)
   {
      switch (ColumnToSort)
      {
         case 0:
         default:
            return (lhs.Caption < rhs.Caption);
         case 1:
            return (lhs.SubItem1 < rhs.SubItem1);
         case 2:
            return (lhs.SubItem2 < rhs.SubItem2);
      }
   }
};
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkChange(TObject *Sender, TListItem *Item, TItemChange Change)
{
   std::sort(vecAddressbk.begin(), vecAddressbk.end(), sAddressbkDataSortComparer());
   lvAddressbk->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::lvAddressbkCustomDraw(TCustomListView *Sender, const TRect &ARect, bool &DefaultDraw)
{
   lvAddressbk->Canvas->Font->Color = clBlue;     
}
//---------------------------------------------------------------------------
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Mon Feb 06, 2012 7:44 pm

.
Last edited by Smoke1 on Sat Feb 11, 2012 4:12 pm, edited 1 time in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Re: C++ Builder IdPOP3 ListView

Postby gambit47 » Mon Feb 06, 2012 11:40 pm

Smoke1 wrote:How do I call the sort on button1 so its sort when the list comes up? on Button1click.


I showed you how to sort the data on demand. Simply sort it after loading it before displaying it, eg:

Code: Select all
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ...
    lAddressbk->Sort(&sAddressbkDataSortProc);
    lvAddressbk->Items->Count = lAddressbk->Count;
}


Code: Select all
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ...
    std::sort(vecAddressbk.begin(), vecAddressbk.end(), sAddressbkDataSortComparer());
    lvAddressbk->Items->Count = vecAddressbk.size();
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 974
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: C++ Builder IdPOP3 ListView

Postby Smoke1 » Tue Feb 07, 2012 12:38 am

Thank you Gambit47your help and Time...
Last edited by Smoke1 on Sat Feb 11, 2012 4:13 pm, edited 4 times in total.
Smoke1
If you think education is difficult, try being stupid.
User avatar
Smoke1
BCBJ Veteran
BCBJ Veteran
 
Posts: 51
Joined: Sat Jan 21, 2012 12:03 pm
Location: Gainesville, Fla.

Next

Return to Technical

Who is online

Users browsing this forum: No registered users and 2 guests

cron