home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Multimed / Multimed.zip / mp3osr05.zip / src / mp3list.pas < prev    next >
Pascal/Delphi Source File  |  1999-12-27  |  20KB  |  716 lines

  1. (*
  2.  * part of MPEG searcher project
  3.  *  (c) 1999 by Alexander Trunov, 2:5069/10, jnc@mail.ru
  4.  *)
  5.  
  6. unit MP3List;
  7.  
  8. interface
  9.  
  10. {$IFNDEF virtualpascal}
  11.   {$IFNDEF fpc}
  12.     {$DEFINE bp}
  13.   {$ENDIF}
  14. {$ENDIF}
  15. {$I-}
  16.  
  17. uses
  18.   Dialogs, Objects, Views, DOS, Drivers, TagEdit, Sortings, mp3lb, Reports,
  19.   SortType, Config, InfoPane
  20.   {$IFDEF fpc}, Commands{$ENDIF}
  21.   {$IFDEF virtualpascal}, VPUtils{$ENDIF}
  22.   ;
  23.  
  24. const
  25.   cmTagEdit = 206;
  26.   cmListRemove = 207;
  27.   cmListAdd = 208;
  28.   cmListGenerate = 209;
  29.   cmListSort = 210;
  30.   cmTagsUpdate = 212;
  31.  
  32. var
  33.   mp3s: PCollection;
  34.  
  35. type
  36.   PMP3List = ^TMP3List;
  37.   TMP3List = object(TDialog)
  38.  
  39.     lstList: PMP3ListBox;
  40.     lblTitle,
  41.       lblArtist,
  42.       lblAlbum,
  43.       lblComment,
  44.       lblYear,
  45.       lblSize: PStaticText;
  46.  
  47.     destructor Done; virtual;
  48.     constructor Init(mp3z: PCollection);
  49.     procedure HandleEvent(var Event: TEvent); virtual;
  50.     function SeparateAndSort(firstFactor,
  51.       secondFactor: TSepFactor): PCollection;
  52.   private
  53.     procedure UpdateInfo(readTags: Boolean);
  54.     procedure PathFilenameSort;
  55.     procedure FilenameSort;
  56.     procedure TwoItemsSort(firstFactor, secondFactor: TSepFactor);
  57.     procedure RandomSort;
  58.   end;
  59.  
  60. implementation
  61.  
  62. uses
  63.   MsgBox, ID3v1, StdDlg, App, Codepage, MP3Opt, StatusW, SortOpt, Wizard
  64.   {$IFNDEF fpc}, EditChD{$ENDIF};
  65.  
  66. {$I nonfpc.inc}
  67.  
  68. function GetMP3Tag(FN: string): PjID3v1;
  69. var
  70.   stream: PDosStream;
  71.   tag: PTagData;
  72.   mp3: Pmp3;
  73.   cp: Byte;
  74.  
  75.   function SearchTag(const Filename: string): Pmp3;
  76.   var
  77.     i: Integer;
  78.     mp3: Pmp3;
  79.   begin
  80.     Result := nil;
  81.     for i := 0 to mp3s^.Count - 1 do
  82.     begin
  83.       mp3 := Pmp3(mp3s^.Items^[i]);
  84.       if mp3^.Filename = Filename then
  85.       begin
  86.         Result := mp3;
  87.         Exit;
  88.       end;
  89.     end;
  90.   end;
  91.  
  92. begin
  93.  
  94.   mp3 := SearchTag(FN);
  95.  
  96.   if (mp3 = nil) or (mp3^.tag = nil) then
  97.   begin
  98.     GetMem(Result, SizeOf(TjID3v1));
  99.     stream := New(PDosStream, Init(FN, stOpenRead));
  100.     tag := New(PTagData, Init(stream));
  101.  
  102.     tag^.ReadTag;
  103.  
  104.     if rpUseCodepage then
  105.     begin
  106.       with tag^.tag do
  107.       begin
  108.         cp := DetermineCodepage(Songname + Artist + Album + Comment);
  109.         Songname := X2Y(Songname, cp, rpCodepage);
  110.         Artist := X2Y(Artist, cp, rpCodepage);
  111.         Album := X2Y(Album, cp, rpCodepage);
  112.         Comment := X2Y(Comment, cp, rpCodepage);
  113.       end;
  114.     end;
  115.     Move(tag^.tag, Result^, SizeOf(TjID3v1));
  116.  
  117.     if mp3 <> nil then
  118.     begin
  119.       GetMem(mp3^.tag, SizeOf(TjID3v1));
  120.       Move(tag^.tag, mp3^.tag^, SizeOf(TjID3v1));
  121.     end;
  122.  
  123.     Dispose(tag, Done);
  124.     Dispose(stream, Done);
  125.   end
  126.   else
  127.   begin
  128.     GetMem(Result, SizeOf(TjID3v1));
  129.     if rpUseCodepage then
  130.     begin
  131.       with mp3^.tag^ do
  132.       begin
  133.         cp := DetermineCodepage(Songname + Artist + Album + Comment);
  134.         Songname := X2Y(Songname, cp, rpCodepage);
  135.         Artist := X2Y(Artist, cp, rpCodepage);
  136.         Album := X2Y(Album, cp, rpCodepage);
  137.         Comment := X2Y(Comment, cp, rpCodepage);
  138.       end;
  139.     end;
  140.     Move(mp3^.tag^, Result^, SizeOf(TjID3v1));
  141.   end;
  142.  
  143. end;
  144.  
  145. destructor TMP3List.Done;
  146. begin
  147.   lstList^.NewList(nil);
  148.   inherited Done;
  149. end;
  150.  
  151. constructor TMP3List.Init(mp3z: PCollection);
  152. var
  153.   R: TRect;
  154. begin
  155.  
  156.   R.Assign(0, 0, 75, 15);
  157.   inherited Init(R, 'MPEGs list');
  158.   Options := Options or ofCentered;
  159.  
  160.   mp3s := mp3z;
  161.  
  162.   R.Assign(2, 2, 33, 13);
  163.   lstList := New(PMP3ListBox, Init(R, nil));
  164.   Insert(lstList);
  165.   lstList^.NewList(mp3s);
  166.  
  167.   R.Assign(34, 2, 40, 3);
  168.   Insert(New(PStaticText, Init(R, ' Tag:')));
  169.  
  170.   R.Assign(40, 2, 54, 4);
  171.   Insert(New(PButton, Init(R, '~E~dit tag', cmTagEdit, 0)));
  172.  
  173.   R.Assign(55, 2, 74, 4);
  174.   Insert(New(PButton, Init(R, '~U~pdate list', cmTagsUpdate, 0)));
  175.  
  176.   R.Assign(34, 4, 74, 5);
  177.   lblTitle := New(PStaticText, Init(R, 'Title  :                               '));
  178.   Insert(lblTitle);
  179.  
  180.   R.Assign(34, 5, 74, 6);
  181.   lblArtist := New(PStaticText, Init(R, 'Artist :                               '));
  182.   Insert(lblArtist);
  183.  
  184.   R.Assign(34, 6, 74, 7);
  185.   lblAlbum := New(PStaticText, Init(R, 'Album  :                               '));
  186.   Insert(lblAlbum);
  187.  
  188.   R.Assign(34, 7, 74, 8);
  189.   lblComment := New(PStaticText, Init(R, 'Comment:                               '));
  190.   Insert(lblComment);
  191.  
  192.   R.Assign(34, 8, 50, 9);
  193.   lblYear := New(PStaticText, Init(R, 'Year   :     '));
  194.   Insert(lblYear);
  195.  
  196.   R.Assign(51, 8, 70, 9);
  197.   lblSize := New(PStaticText, Init(R, 'Size:              '));
  198.   Insert(lblSize);
  199.  
  200.   UpdateInfo(false);
  201.  
  202.   R.Assign(34, 10, 41, 11);
  203.   Insert(New(PStaticText, Init(R, ' List:')));
  204.  
  205.   R.Assign(40, 10, 54, 12);
  206.   Insert(New(PButton, Init(R, 'A~d~d item', cmListAdd, 0)));
  207.  
  208.   R.Assign(55, 10, 74, 12);
  209.   Insert(New(PButton, Init(R, '~R~emove item', cmListRemove, 0)));
  210.  
  211.   R.Assign(40, 12, 59, 14);
  212.   Insert(New(PButton, Init(R, '~G~enerate list', cmListGenerate, 0)));
  213.  
  214.   R.Assign(59, 12, 74, 14);
  215.   Insert(New(PButton, Init(R, '~S~ort list', cmListSort, 0)));
  216.  
  217.   lstList^.Select;
  218.  
  219. end;
  220.  
  221. procedure TMP3List.UpdateInfo(readTags: Boolean);
  222. var
  223.   mp3: Pmp3;
  224.   cp: Byte;
  225. begin
  226.  
  227.   lstList^.List^.Pack;
  228.  
  229.   if lstList^.Range = 0 then
  230.   begin
  231.     lblTitle^.Text^ := 'Title  :';
  232.     lblArtist^.Text^ := 'Artist :';
  233.     lblAlbum^.Text^ := 'Album  :';
  234.     lblComment^.Text^ := 'Comment:';
  235.     lblYear^.Text^ := 'Year   :';
  236.     lblSize^.Text^ := 'Size:';
  237.  
  238.     ReDraw;
  239.     Exit;
  240.   end;
  241.  
  242.   if lstList^.Focused > lstList^.List^.Count - 1 then
  243.   begin
  244.     lstList^.FocusItem(0);
  245.   end;
  246.  
  247.   mp3 := mp3s^.Items^[lstList^.Focused];
  248.   if readTags then
  249.     mp3^.ReadTagNow;
  250.   if mp3^.tag = nil then
  251.   begin
  252.     mp3^.tag := GetMP3Tag(mp3^.Filename);
  253.   end;
  254.  
  255.   with mp3^.tag^ do
  256.   begin
  257.  
  258.     { codepage stuff }
  259.  
  260.     if rpUseCodepage then
  261.     begin
  262.       cp := DetermineCodepage(Songname + Artist + Album + Comment);
  263.       Songname := X2Y(Songname, cp, rpCodepage);
  264.       Artist := X2Y(Artist, cp, rpCodepage);
  265.       Album := X2Y(Album, cp, rpCodepage);
  266.       Comment := X2Y(Comment, cp, rpCodepage);
  267.     end;
  268.  
  269.     { labels stuff }
  270.  
  271.     lblTitle^.Text^ := 'Title  : ' + Songname;
  272.     lblArtist^.Text^ := 'Artist : ' + Artist;
  273.     lblAlbum^.Text^ := 'Album  : ' + Album;
  274.     lblComment^.Text^ := 'Comment: ' + Comment;
  275.     lblYear^.Text^ := 'Year   : ' + Year;
  276.     lblSize^.Text^ := 'Size: ' + Long2StrFmt(Size);
  277.   end;
  278.  
  279.   ReDraw;
  280. end;
  281.  
  282. {$I sort.inc}
  283.  
  284. var
  285.   compareFactor: TSepFactor;
  286.  
  287. function ShortGetMP3Tag(mp3: Pmp3): PjID3v1;
  288. begin
  289.   GetMem(Result, SizeOf(TjID3v1));
  290.   FillChar(Result^, SizeOf(TjID3v1), 0);
  291.   if mp3^.tag = nil then
  292.     Exit;
  293.   Move(mp3^.tag^, Result^, SizeOf(TjID3v1));
  294. end;
  295.  
  296. function ItemCompare(item1, item2: Pointer): Integer;
  297. var
  298.   tag1, tag2: PjID3v1;
  299.   cmpItem1, cmpItem2: string;
  300. begin
  301.   tag1 := ShortGetMP3Tag(Pmp3(item1));
  302.   tag2 := ShortGetMP3Tag(Pmp3(item2));
  303.  
  304.   case compareFactor of
  305.     faAlbum:
  306.       begin cmpItem1 := tag1^.Album; cmpItem2 := tag2^.Album;
  307.       end;
  308.     faArtist:
  309.       begin cmpItem1 := tag1^.Artist; cmpItem2 := tag2^.Artist;
  310.       end;
  311.     faTitle:
  312.       begin cmpItem1 := tag1^.Songname; cmpItem2 := tag2^.Songname;
  313.       end;
  314.     faComment:
  315.       begin cmpItem1 := tag1^.Comment; cmpItem2 := tag2^.Comment;
  316.       end;
  317.     faYear:
  318.       begin cmpItem1 := tag1^.Year; cmpItem2 := tag2^.Year;
  319.       end;
  320.   end;
  321.  
  322.   Result := StringCompare(@cmpItem1, @cmpItem2);
  323.  
  324.   FreeMem(tag1, SizeOf(tag1^));
  325.   FreeMem(tag2, SizeOf(tag2^));
  326. end;
  327.  
  328. function CollectionItemCompare(item1, item2: Pointer): Integer;
  329. var
  330.   tag1, tag2: PjID3v1;
  331.   cmpItem1, cmpItem2: string;
  332. begin
  333.   tag1 := ShortGetMP3Tag(Pmp3(PCollection(item1)^.Items^[0]));
  334.   tag2 := ShortGetMP3Tag(Pmp3(PCollection(item2)^.Items^[0]));
  335.  
  336.   case compareFactor of
  337.     faAlbum:
  338.       begin cmpItem1 := tag1^.Album; cmpItem2 := tag2^.Album;
  339.       end;
  340.     faArtist:
  341.       begin cmpItem1 := tag1^.Artist; cmpItem2 := tag2^.Artist;
  342.       end;
  343.     faTitle:
  344.       begin cmpItem1 := tag1^.Songname; cmpItem2 := tag2^.Songname;
  345.       end;
  346.     faComment:
  347.       begin cmpItem1 := tag1^.Comment; cmpItem2 := tag2^.Comment;
  348.       end;
  349.     faYear:
  350.       begin cmpItem1 := tag1^.Year; cmpItem2 := tag2^.Year;
  351.       end;
  352.   end;
  353.  
  354.   Result := StringCompare(@cmpItem1, @cmpItem2);
  355.  
  356.   FreeMem(tag1, SizeOf(tag1^));
  357.   FreeMem(tag2, SizeOf(tag2^));
  358. end;
  359.  
  360. function FilenameCompare(item1, item2: Pointer): Integer;
  361. var
  362.   str1, str2: string;
  363. begin
  364.   str1 := ExtractFilename(Pmp3(item1)^.Filename);
  365.   str2 := ExtractFilename(Pmp3(item2)^.Filename);
  366.   Result := StringCompare(@str1, @str2);
  367. end;
  368.  
  369. function PathFilenameCompare(item1, item2: Pointer): Integer;
  370. begin
  371.   Result := StringCompare(@Pmp3(item1)^.Filename, @Pmp3(item2)^.Filename);
  372. end;
  373.  
  374. procedure TMP3List.PathFilenameSort;
  375. begin
  376.   QuickSort(mp3s^.Items, 0, mp3s^.Count - 1, PathFilenameCompare);
  377. end;
  378.  
  379. procedure TMP3List.FilenameSort;
  380. begin
  381.   QuickSort(mp3s^.Items, 0, mp3s^.Count - 1, FilenameCompare);
  382. end;
  383.  
  384. function TMP3List.SeparateAndSort(firstFactor,
  385.   secondFactor: TSepFactor): PCollection;
  386. var
  387.   bigColl: PCollection;
  388.   coll: PCollection;
  389.   i, j: Integer;
  390. begin
  391.  
  392.   // 1. make big collection that will contain small collections
  393.  
  394.   bigColl := SeparateCollection(firstFactor, mp3s, GetMP3Tag);
  395.  
  396.   // 2. sort small collections
  397.  
  398.   compareFactor := secondFactor;
  399.   for i := 0 to bigColl^.Count - 1 do
  400.   begin
  401.     coll := PCollection(bigColl^.Items^[i]);
  402.     QuickSort(coll^.Items, 0, coll^.Count - 1, ItemCompare);
  403.   end;
  404.  
  405.   // 3. sort big collection
  406.  
  407.   compareFactor := firstFactor;
  408.   QuickSort(bigColl^.Items, 0, bigColl^.Count - 1, CollectionItemCompare);
  409.  
  410.   Result := bigColl;
  411.  
  412. end;
  413.  
  414. procedure TMP3List.TwoItemsSort(firstFactor, secondFactor: TSepFactor);
  415. var
  416.   bigColl: PCollection;
  417.   coll: PCollection;
  418.   i, j: Integer;
  419. begin
  420.  
  421.   bigColl := SeparateAndSort(firstFactor, secondFactor);
  422.  
  423.   // 4. make mp3s collection from bigColl
  424.  
  425.   for i := 0 to bigColl^.Count - 1 do
  426.   begin
  427.     coll := PCollection(bigColl^.Items^[i]);
  428.     for j := 0 to coll^.Count - 1 do
  429.     begin
  430.       mp3s^.AtInsert(mp3s^.Count, NewStr(PString(coll^.Items^[j])^));
  431.     end;
  432.   end;
  433.  
  434.   Dispose(bigColl, Done);
  435.  
  436.   // 5. yeeeeeehaaaw ;-) with no memory leaks from first attempt..
  437.   // as usually, by the way ;-)
  438.  
  439. end;
  440.  
  441. procedure TMP3List.RandomSort;
  442. var
  443.   dupColl: PCollection;
  444.   i, j: Integer;
  445.   p: Pointer;
  446. begin
  447.   dupColl := New(PCollection, Init(10, 10));
  448.   Randomize;
  449.  
  450.   for i := 0 to mp3s^.Count - 1 do
  451.   begin
  452.     dupColl^.Insert(mp3s^.Items^[i]);
  453.   end;
  454.  
  455.   for i := 0 to mp3s^.Count - 1 do
  456.   begin
  457.     p := nil;
  458.     while p = nil do
  459.     begin
  460.       j := Random(mp3s^.Count);
  461.       p := dupColl^.Items^[j];
  462.     end;
  463.     dupColl^.Items^[j] := nil;
  464.     mp3s^.Items^[i] := p;
  465.   end;
  466.  
  467.   dupColl^.DeleteAll;
  468.  
  469.   Dispose(dupColl, Done);
  470. end;
  471.  
  472. procedure TMP3List.HandleEvent(var Event: TEvent);
  473. var
  474.   dlg: PDialog;
  475.   theFile: FNameStr;
  476.   option: Integer;
  477.   factor: TSepFactor;
  478.   twoItemsRec: TTwoItemsRec;
  479.   tplNum: Byte;
  480.   tempColl: PStringCollection;
  481.  
  482.  function MakeShortColl(tpls: PStringCollection): PStringCollection;
  483.  var
  484.    i: Integer;
  485.  begin
  486.    Result := New(PStringCollection, Init(10, 10));
  487.    for i := 0 to tpls^.Count - 1 do
  488.    begin
  489.      Result^.AtInsert(Result^.Count,
  490.        NewStr(JustFileName(PString(tpls^.At(i))^)));
  491.    end;
  492.  end;
  493.  
  494. begin
  495.   inherited HandleEvent(Event);
  496.  
  497.   case Event.What of
  498.     evKeyDown:
  499.       begin
  500.         case Event.KeyCode of
  501.           kbF2:
  502.             begin
  503.               dlg := New(PMpegInfo,
  504.                 Init(Pmp3(mp3s^.At(lstList^.Focused))^.tag));
  505.               Application^.ExecuteDialog(dlg, nil);
  506.             end;
  507.         end;
  508.       end;
  509.     evBroadcast, evCommand:
  510.       begin
  511.         case Event.Command of
  512.           cmTagsUpdate:
  513.             begin
  514.               UpdateInfo(true);
  515.               ClearEvent(Event);
  516.             end;
  517.           cmListItemSelected, cmListItemFocused:
  518.             begin
  519.  
  520.               if (lstList = nil) or (mp3s = nil) or (lblTitle = nil) or
  521.                 (lblArtist = nil) or (lblAlbum = nil) or (lblComment = nil) or
  522.                 (lblYear = nil) then
  523.                 Exit;
  524.  
  525.               UpdateInfo(false);
  526.  
  527.               ClearEvent(Event);
  528.             end;
  529.           cmTagEdit:
  530.             begin
  531.               if lstList^.Range = 0 then
  532.                 Exit;
  533.               dlg := New(PTagEditor, Init(
  534.                 Pmp3(mp3s^.Items^[lstList^.Focused])^.Filename));
  535.  
  536.               if Application^.ExecuteDialog(dlg, nil) = cmOk then
  537.               begin
  538.                 UpdateInfo(false);
  539.               end;
  540.  
  541.               ClearEvent(Event);
  542.             end;
  543.           cmListRemove:
  544.             begin
  545.               if lstList^.Range = 0 then
  546.                 Exit;
  547.               mp3s^.FreeItem(mp3s^.At(lstList^.Focused));
  548.               mp3s^.AtDelete(lstList^.Focused);
  549.  
  550.               lstList^.SetRange(mp3s^.Count);
  551.               lstList^.Draw;
  552.               UpdateInfo(false);
  553.  
  554.               ClearEvent(Event);
  555.             end;
  556.           cmListAdd:
  557.             begin
  558.               theFile := '*.*';
  559.               if OpenFile(theFile, 214) then
  560.               begin
  561.                 mp3s^.Insert(New(Pmp3, Init(theFile, true)));
  562.                 lstList^.SetRange(mp3s^.Count);
  563.                 lstList^.Draw;
  564.                 UpdateInfo(false);
  565.               end;
  566.               ClearEvent(Event);
  567.             end;
  568.           cmListGenerate:
  569.             begin
  570.               dlg := New(PMP3Options, Init); option := 0;
  571.  
  572.               if Application^.ExecuteDialog(dlg, @option) = cmOk then
  573.               begin
  574.                 theFile := ExtractDir(ParamStr(0));
  575.                 ChDir(Copy(theFile, 1, Length(theFile) - 1));
  576.                 case option of
  577.                   0:
  578.                     begin
  579.                       theFile := '*.m3u';
  580.                       if SaveAs(theFile, 215) then
  581.                       begin
  582.                         if SaveM3U(theFile, mp3s, GetMP3Tag) then
  583.                           MessageBox(#3'Internet-playlist successfully created.',
  584.                             nil, mfInformation or mfOkButton);
  585.                       end;
  586.                     end;
  587.                   1:
  588.                     begin
  589.                       theFile := '*.bbs';
  590.                       if SaveAs(theFile, 215) then
  591.                       begin
  592.                         if SaveFilesBBS(theFile, mp3s, GetMP3Tag) then
  593.                           MessageBox(#3'files.bbs successfully created.',
  594.                             nil, mfInformation or mfOkButton);
  595.                       end;
  596.                     end;
  597.                   2:
  598.                     begin
  599.                       tplNum := 0;
  600.                       if tplWhole^.Count = 0 then
  601.                       begin
  602.                         MessageBox('There is no templates available.', nil,
  603.                           mfError or mfOkButton);
  604.                         Exit;
  605.                       end;
  606.                       tempColl := MakeShortColl(tplWhole);
  607.                       dlg := New(PTemplateDialog, Init(tempColl));
  608.                       Dispose(tempColl, Done);
  609.                       if Application^.ExecuteDialog(dlg, @tplNum) = cmCancel then
  610.                         Exit;
  611.                       theFile := '*.rpt';
  612.                       if SaveAs(theFile, 215) then
  613.                       begin
  614.                         if SaveListWhole(theFile,
  615.                           PString(tplWhole^.Items^[tplNum])^, mp3s,
  616.                           GetMP3Tag) then
  617.                         begin
  618.                           MessageBox(#3'List successfully created.',
  619.                             nil, mfInformation or mfOkButton);
  620.                         end;
  621.                       end;
  622.                     end;
  623.                   3:
  624.                     begin
  625.                       tplNum := 0;
  626.                       if tplBy^.Count = 0 then
  627.                       begin
  628.                         MessageBox('There is no templates available.', nil,
  629.                           mfError or mfOkButton);
  630.                         Exit;
  631.                       end;
  632.                       tempColl := MakeShortColl(tplBy);
  633.                       dlg := New(PTemplateDialog, Init(tempColl));
  634.                       Dispose(tempColl, Done);
  635.                       if Application^.ExecuteDialog(dlg, @tplNum) = cmCancel then
  636.                         Exit;
  637.                       theFile := '*.rpt';
  638.                       if SaveAs(theFile, 215) then
  639.                         dlg := New(PTwoItemsDialog, Init('Separate by'));
  640.                         with twoItemsRec do
  641.                         begin
  642.                           firstFactor := faArtist;
  643.                           secondFactor := faArtist;
  644.                         end;
  645.                         if Application^.ExecuteDialog(dlg, @twoItemsRec) = cmOk then
  646.                           if SaveSeparatedList(theFile,
  647.                             PString(tplBy^.Items^[tplNum])^, mp3s, GetMP3Tag,
  648.                             twoItemsRec) then
  649.                           begin
  650.                             MessageBox(#3'List successfully created.', nil,
  651.                               mfInformation or mfOkButton);
  652.                           end;
  653.                     end;
  654.                 end;
  655.               end;
  656.               ClearEvent(Event);
  657.             end;
  658.           cmListSort:
  659.             begin
  660.               dlg := New(PSortOptions, Init);
  661.               mp3s^.Pack;
  662.  
  663.               option := 0;
  664.               if Application^.ExecuteDialog(dlg, @option) = cmOk then
  665.               begin
  666.                 case option of
  667.                   0:
  668.                     begin
  669.                       PathFilenameSort;
  670.                     end;
  671.                   1:
  672.                     begin
  673.                       FilenameSort;
  674.                     end;
  675.                   2:
  676.                     begin
  677.                       factor := faArtist;
  678.                       dlg := New(POneItemDialog, Init);
  679.                       if Application^.ExecuteDialog(dlg, @factor) = cmOk then
  680.                       begin
  681.                         compareFactor := factor;
  682.                         QuickSort(mp3s^.Items, 0, mp3s^.Count - 1, ItemCompare);
  683.                       end;
  684.                     end;
  685.                   3:
  686.                     begin
  687.                       with twoItemsRec do
  688.                       begin
  689.                         firstFactor := faArtist;
  690.                         secondFactor := faArtist;
  691.                       end;
  692.                       dlg := New(PTwoItemsDialog, Init('Sort by'));
  693.                       if Application^.ExecuteDialog(dlg,
  694.                         @twoItemsRec) = cmOk then
  695.                       begin
  696.                         with twoItemsRec do
  697.                           TwoItemsSort(firstFactor, secondFactor);
  698.                       end;
  699.                     end;
  700.                   4:
  701.                     begin
  702.                       RandomSort;
  703.                     end;
  704.                 end;
  705.                 UpdateInfo(false);
  706.               end;
  707.  
  708.               ClearEvent(Event);
  709.             end;
  710.         end;
  711.       end;
  712.   end;
  713. end;
  714.  
  715. end.
  716.